diff --git a/3.0/client/PHP/Gallery3.php b/3.0/client/PHP/Gallery3.php index 83ed7b2d..fb97ddf8 100644 --- a/3.0/client/PHP/Gallery3.php +++ b/3.0/client/PHP/Gallery3.php @@ -1,7 +1,7 @@ + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/3.0/client/Python/pylibgal3/MANIFEST.in b/3.0/client/Python/pylibgal3/MANIFEST.in new file mode 100644 index 00000000..3ca15d46 --- /dev/null +++ b/3.0/client/Python/pylibgal3/MANIFEST.in @@ -0,0 +1,2 @@ +include KNOWN_ISSUES +include LICENSE diff --git a/3.0/client/Python/pylibgal3/README b/3.0/client/Python/pylibgal3/README new file mode 100644 index 00000000..57114ce3 --- /dev/null +++ b/3.0/client/Python/pylibgal3/README @@ -0,0 +1,21 @@ +======= +Install +======= + +To install this libary, just do the usual Python setup: + +# tar -xvzf libgal3-*.tar.gz +# cd libgal3-* +# python setup.py install + +That's it for install. You should be able to import the libg3 library after +that: + +(In your python script) +import libg3 + +============= +Documentation +============= + +See http://stuffivelearned.org/doku.php?id=programming:python:libgal3 for documentation info. diff --git a/3.0/client/Python/pylibgal3/libg3/Errors.py b/3.0/client/Python/pylibgal3/libg3/Errors.py new file mode 100644 index 00000000..399bc259 --- /dev/null +++ b/3.0/client/Python/pylibgal3/libg3/Errors.py @@ -0,0 +1,51 @@ +# +# Author: Jay Deiman +# Email: admin@splitstreams.com +# +# This file is part of pylibgal3. +# +# pylibgal3 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pylibgal3 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pylibgal3. If not, see . +# + +__all__ = ['G3Error' , 'G3RequestError' , 'G3InvalidRespError' , + 'G3UnknownTypeError' , 'G3AuthError' , 'G3UnknownError'] + +class G3Error(Exception): + pass + +class G3RequestError(G3Error): + def __init__(self , errDict): + self.errors = errDict + self._message = self._getMessage() + + def _getMessage(self): + ret = '' + for e in self.errors.items(): + ret += '%s: %r\n' % e + return ret + + def __str__(self): + return self._message + +class G3InvalidRespError(G3Error): + pass + +class G3UnknownTypeError(G3InvalidRespError): + pass + +class G3AuthError(G3Error): + pass + +class G3UnknownError(G3Error): + pass diff --git a/3.0/client/Python/pylibgal3/libg3/G3Items.py b/3.0/client/Python/pylibgal3/libg3/G3Items.py new file mode 100644 index 00000000..0fdae593 --- /dev/null +++ b/3.0/client/Python/pylibgal3/libg3/G3Items.py @@ -0,0 +1,502 @@ +# +# Author: Jay Deiman +# Email: admin@splitstreams.com +# +# This file is part of pylibgal3. +# +# pylibgal3 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pylibgal3 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pylibgal3. If not, see . +# + +__all__ = ['Album' , 'Image' , 'LocalImage' , 'RemoteImage' , 'LocalMovie' , + 'RemoteMovie' , 'getItemFromResp' , 'getItemsFromResp'] + +from datetime import datetime +import json , weakref , types , os , mimetypes , re + +class BaseRemote(object): + def __init__(self , respObj , weakGalObj , weakParent=None): + self._setAttrItems(respObj.items()) + if 'entity' in respObj: + self._setAttrItems(respObj['entity'].items()) + self._weakParent = None + if weakParent is not None: + self._weakParent = weakParent + self._weakGal = weakGalObj + self.fh = None + self._postInit() + + def __str__(self): + try: + return self.title + except: + pass + return self.name + + def __getattr__(self , name): + """ + A bit of magic to make the retrieval of member objects lazy + """ + # Process the specials + if name == 'members': + self.members = self._getMemberObjects() + return self.members + if name == 'tags': + self.tags = self._getTags() + return self.tags + if name == 'comments': + self.comments = self._getComments() + return self.comments + # Process the weak reference calls + if name == '_gal': + return self._weakGal() + if name == 'parent' and self._weakParent is not None: + return self._weakParent() + # Process the generic items + urlAttr = '_%s' % name + # Call __getattribute__ to prevent loops + attr = object.__getattribute__(self , urlAttr) + if attr is not None and attr.startswith('http'): + obj = self._getUrlObject(attr) + setattr(self , name , obj) + return obj + raise AttributeError(name) + + def _postInit(self): + """ + This can be overridden in subclasses to do any special initialization + at the end of the __init__ call + """ + pass + + def _setAttrItems(self , d): + for k , v in d: + if k == 'entity': + # Skip it + continue + if (type(v) in types.StringTypes and v.startswith('http') and + 'url' not in k) or k == 'members': + setattr(self , '_%s' % k , v) + else: + setattr(self , k , v) + + def _getMemberObjects(self): + """ + This returns the appropriate objects for each child of this object. + The default "members" attribute only contains the URLs for the + children of this object. This returns a list of the actual objects. + """ + memObjs = self._gal.getItemsForUrls(self._members , self) + return memObjs + + def _getTags(self): + """ + Returns the list of tag objects + + returns(list[Tag]) + """ + # First, I want just the actual tag itself, not the RESTy "tag_item", + # so I'm going to modify the urls to save a step + ret = [] + urls = [] + for url in self.relationships['tags']['members']: + m = re.match('^(.*?/tag)_item(/\d+),\d+$' , url) + urls.append('%s%s' % tuple(m.groups())) + if urls: + for url in urls: + resp = self._gal.getRespFromUrl(url) + ret.append(getItemFromResp(resp , self._gal , self)) + return ret + + def _getComments(self): + """ + Returns a list of the Comment items for this item + + returns(list[Comment]) : Returns a list of Comment objects + """ + ret = [] + # I can't use the shortcut I did for tags so I need to get the list + # of comments in the first call and then create the objects with + # the calls thereafter + commListUrl = self.relationships['comments']['url'] + resp = self._gal.getRespFromUrl(commListUrl) + tmpObj = json.loads(resp.read()) + for url in tmpObj['members']: + resp = self._gal.getRespFromUrl(url) + ret.append(getItemFromResp(resp , self._gal , self)) + return ret + + def _getUrlObject(self , url): + """ + This returns the album cover image + """ + resp = self._gal.getRespFromUrl(url) + return getItemFromResp(resp , self._gal , self) + + def getCrDT(self): + """ + Returns a datetime object for the time this item was created + """ + if hasattr(self , 'created'): + return datetime.fromtimestamp(int(self.created)) + return None + + def getUpdDT(self): + """ + Returns a datetime object for the time this item was last updated + """ + if hasattr(self , 'updated'): + return datetime.fromtimestamp(int(self.updated)) + return None + + def delete(self): + """ + Deletes this + + returns(tuple(status , msg)) : Returns a tuple of a boolean status + and a message if there is an error + """ + return self._gal.deleteItem(self) + + def update(self , title=None , description=None): + """ + Update either the title, the description or both + + title(str) : The new item title + description(str) : The new item description + + returns(tuple(status , msg)) : Returns a tuple of a boolean status + and a message if there is an error + """ + if title is not None: + self.title = title + if description is not None: + self.description = description + return self._gal.updateItem(self) + + def tag(self , tagName): + """ + Tag this item with the string "tagName" + + tagName(str) : The actual tag name + + returns(Tag) : The tag that was created + """ + return self._gal.tagItem(self , tagName) + +class Album(BaseRemote): + def addImage(self , image , title='' , description='' , name=''): + """ + Add a LocalImage object to the album + + image(LocalImage) : The image to upload + + returns(RemoteImage) : The RemoteImage object that was created + """ + if not isinstance(image , LocalImage): + raise TypeError('%r is not of type LocalImage' % image) + return self._gal.addImage(self , image , title , description , name) + + def addMovie(self , movie , name='' , title='' , description=''): + """ + Adds a LocalMovie object to the album + + movie(LocalMovie) : The movie to upload + + returns(RemoteMovie) : The RemoteMovie object that was created + """ + return self._gal.addMovie(self , movie , title , description , name) + + def addAlbum(self , albumName , title , description=''): + """ + Add a subalbum to this album + + albumName(str) : The name of the new album + title(str) : The album title + description(str): The album description + + returns(Album) : The Album object that was created + """ + return self._gal.addAlbum(self , albumName , title , description) + + def setCover(self , image): + """ + Sets the album cover to the RemoteImage + + image(RemoteImage) : The image to set as the album cover + + returns(tuple(status , msg)) : Returns a tuple of a boolean status + and a message if there is an error + """ + return self._gal.setAlbumCover(self , image) + + def getAlbums(self): + """ + Return a list of the sub-albums in this album + + returns(list[Album]) : A list of Album objects + """ + return self._getByType('album') + Albums = property(getAlbums) + + def getImages(self): + """ + Return a list of the images in this album + + returns(list[RemoteImage]) : A list of RemoteImages + """ + return self._getByType('photo') + Images = property(getImages) + + def getMovies(self): + """ + Return a list of the movies in this album + + returns(list[RemoteMovie]) : A list of RemoteMovie objects + """ + return self._getByType('movie') + Movies = property(getMovies) + + def getRandomImage(self , direct=True): + """ + Returns a random RemoteImage object for the album. If "direct" is + False, a random image can be pulled from nested albums. + + direct(bool) : If set to False, the image may be pulled from + a sub-album + + returns(RemoteImage) : Returns a RemoteImage instance + """ + return self._gal.getRandomImage(self , direct) + + def _getByType(self , t): + ret = [] + for m in self.members: + if m.type == t: + ret.append(m) + return ret + +class Image(object): + contentType = '' + +class LocalImage(Image): + def __init__(self , path , replaceSpaces=True): + if not os.path.isfile(path): + raise IOError('%s is not a file' % path) + self.path = path + self.replaceSpaces = replaceSpaces + self.Filename = os.path.basename(self.path) + self.fh = None + self.type = 'photo' + + def setContentType(self , ctype=None): + if ctype is not None: + self.contentType = ctype + self.contentType = mimetypes.guess_type(self.getFileContents())[0] or \ + 'application/octet-stream' + def getContentType(self): + if not self.contentType: + self.setContentType() + return self.contentType + ContentType = property(getContentType , setContentType) + + def setFilename(self , name): + self.filename = name + if self.replaceSpaces: + self.filename = self.filename.replace(' ' , '_') + def getFilename(self): + return self.filename + Filename = property(getFilename , setFilename) + + def getFileContents(self): + """ + Gets the entire contents of the file + + returns(str) : File contents + """ + if self.fh is None: + self.fh = open(self.path , 'rb') + self.fh.seek(0) + return self.fh.read() + + def getUploadContent(self): + """ + This will return a string containing the MIME headers and the actual + binary content to be uploaded + """ + ret = 'Content-Disposition: form-data; name="file"; ' + ret += 'filename="%s"\r\n' % self.filename + ret += 'Content-Type: %s\r\n' % self.ContentType + ret += 'Content-Transfer-Encoding: binary\r\n' + ret += '\r\n' + ret += self.getFileContents() + '\r\n' + return ret + + def close(self): + try: + self.fh.close() + except: + pass + +class RemoteImage(BaseRemote , Image): + def addComment(self , comment): + """ + Comment on this item with the string "comment" + + comment(str) : The comment + + returns(Comment) : The comment that was created + """ + return self._gal.addComment(self , comment) + + def read(self , length=None): + if not self.fh: + resp = self._gal.getRespFromUrl(self.file_url) + self.fh = resp + if length is None: + return self.fh.read() + return self.fh.read(int(length)) + + def close(self): + try: + self.fh.close() + except: + pass + + def getResizeHandle(self): + """ + Returns a file-like object (specifically a urllib2.addinfourl) handle + to the "resize" version of the image + + returns(urllib2.addinfourl) : A file-like object handle for retrieving + the resized image + """ + if hasattr(self , 'resize_url'): + resp = self._gal.getRespFromUrl(self.resize_url) + return resp + return None + + def getThumbHandle(self): + """ + Returns a file-like object (specifically a urllib2.addinfourl) handle + to the "thumbnail" version of the image + + returns(urllib2.addinfourl) : A file-like object handle for retrieving + the thumbnail image + """ + if hasattr(self , 'thumb_url'): + resp = self._gal.getRespFromUrl(self.thumb_url) + return resp + return None + +class LocalMovie(LocalImage): + def __init__(self , path , replaceSpaces=True): + LocalImage.__init__(self , path , replaceSpaces) + self.type = 'movie' + +class RemoteMovie(RemoteImage): + pass + +class Tag(BaseRemote): + """ + A simple class to represent a tag + """ + def __str__(self): + return self.name + + def _postInit(self): + if hasattr(self , 'count'): + self.count = int(self.count) + self.type = 'tag' + + def tag(self , tagName): + raise G3Error('You cannot tag a tag') + +class Comment(BaseRemote): + """ + A class to represent a comment + """ + def __str__(self): + return self.text + + def _postInit(self): + # Change the "item" attribute to "parent" since that's what it is + # I'm doing this to address overall consistency + self._parent = None + if hasattr(self , '_item'): + self._parent = getattr(self , '_item') + + def tag(self , tagName): + raise G3Error('You cannot tag a comment') + +def getItemFromResp(response , galObj , parent=None): + """ + Returns the appropriate item given the "addinfourl" response object from + the urllib2 request + + response(addinfourl|dict) : The response object from the urllib2 request + or a dict that has already been converted + (usually when called from getItemsFromResp) + galObj(Gallery3) : The gallery object this is associated with + parent(Album) : The parent object for this item + + returns(BaseRemote) : Returns an implemenation of BaseRemote + """ + galObj = weakref.ref(galObj) + if parent is not None: + parent = weakref.ref(parent) + if isinstance(response , dict): + respObj = response + else: + respObj = json.loads(response.read()) + if 'count' in respObj['entity']: + # This is a tag. It doesn't have the same items as regular objects + return Tag(respObj , galObj , parent) + if 'text' in respObj['entity']: + # This is a comment. It also does not have the same items as + # regular objects + return Comment(respObj , galObj , parent) + try: + t = respObj['entity']['type'] + except: + raise G3InvalidRespError('Response contains no "entity type": %r' % + response) + if t == 'album': + return Album(respObj , galObj , parent) + elif t == 'photo': + return RemoteImage(respObj , galObj , parent) + elif t == 'movie': + return RemoteMovie(respObj , galObj , parent) + else: + raise G3UnknownTypeError('Unknown entity type: %s' % t) + +def getItemsFromResp(response , galObj , parent=None): + """ + This takes the raw response with a list of items and returns a list of + the corresponding objects + + response(addinfourl|dict) : The response object from the urllib2 request + or a dict that has already been converted + (usually when called from getItemsFromResp) + galObj(Gallery3) : The gallery object this is associated with + parent(Album) : The parent object for this item + + returns(list[BaseRemote]) : Returns a list of BaseRemote objects + """ + ret = [] + lResp = json.loads(response.read()) + if not isinstance(lResp , list): + lResp = list(lResp) + for resp in lResp: + ret.append(getItemFromResp(resp , galObj , parent)) + return ret diff --git a/3.0/client/Python/pylibgal3/libg3/Gallery3.py b/3.0/client/Python/pylibgal3/libg3/Gallery3.py new file mode 100644 index 00000000..6345c1a8 --- /dev/null +++ b/3.0/client/Python/pylibgal3/libg3/Gallery3.py @@ -0,0 +1,464 @@ +# +# Author: Jay Deiman +# Email: admin@splitstreams.com +# +# This file is part of pylibgal3. +# +# pylibgal3 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pylibgal3 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pylibgal3. If not, see . +# + +__all__ = ['Gallery3' , 'login'] + +from Requests import * +from Errors import G3RequestError , G3UnknownError +from G3Items import getItemFromResp , getItemsFromResp , BaseRemote , Album , \ + RemoteImage , Tag +from urllib import quote , urlencode +from uuid import uuid4 +import urllib2 , os , json + +class Gallery3(object): + """ + This is the main utility class that should be instantiated and used for all + calls + """ + def __init__(self , host , apiKey , g3Base='/gallery3' , port=80 , + ssl=False): + """ + Initializes and sets up the gallery 3 object + + host(str) : The hostname of the gallery site + apiKey(str) : The api key to use for the connections + g3Base(str) : The remote url path to your gallery 3 install + (default: /gallery3) + port(int) : The port number to connect to (default: 80) + ssl(bool) : If true, use SSL for the connection (default: 80) + """ + self.host = host + self.apiKey = apiKey + self.port = int(port) + self.ssl = ssl + self.g3Base = g3Base.strip('/') + self.protocol = ('http' , 'https')[ssl] + self.root = None + self._rootUri = 'index.php/rest/item/1' + self._opener = None + self._buildOpener() + + def getRoot(self): + """ + Returns the root item (album) + """ + if self.root is None: + resp = self.getRespFromUri(self._rootUri) + self.root = getItemFromResp(resp , self) + return self.root + + def getRandomImage(self , album , direct=True): + """ + Returns a random RemoteImage object for the album. If "direct" is + False, a random image can be pulled from nested albums. + + album(Album) : The album object to pull the random image from + direct(bool) : If set to False, the image may be pulled from + a sub-album + + returns(RemoteImage) : Returns a RemoteImage instance + """ + scope = ('all' , 'direct')[direct] + data = { + 'type': 'photo' , + 'random': 'true' , + 'scope': scope , + } + url = '%s?%s' % (album.url , urlencode(data)) + resp = self.getRespFromUrl(url) + return getItemFromResp(resp , self) + + def getItemsForUrls(self , urls , parent=None): + """ + This retrieves an item for each url specified in the urls list + + urls(list[str]) : The list of urls to retrieve + + returns(list[BaseRemote]) : Returns a list of the corresponding + remote objects + """ + numUrls = len(urls) + start = 0 + increment = 25 + ret = [] + while start < numUrls: + data = { + 'urls': json.dumps(urls[start:start+increment]) , + 'num': str(increment) , + 'start': str(start) , + } + resp = self.getRespFromUri('index.php/rest/items' , data) + ret.extend(getItemsFromResp(resp , self , parent)) + start += increment + return ret + + def getRespFromUrl(self , url): + """ + This returns the response object given a full url rather than just a + uri defining the location on the server + + url(str) : The url to the resource + """ + req = GetRequest(url , self.apiKey) + resp = self._openReq(req) + return resp + + def getRespFromUri(self , uri , kwargs={}): + """ + Performs the request for the given uri and returns the "addinfourl" + response + + uri(str) : The uri string defining the resource on the defined host + """ + url = self._buildUrl(uri , kwargs) + print url + return self.getRespFromUrl(url) + + def addAlbum(self , parent , albumName , title , description=''): + """ + Adds an album to the given parent album + + parent(Album) : The parent Album object + albumName(str) : The name of the album + title(str) : The album title + description(str) : The album description + + returns(Album) : The Album object that was created + """ + if not parent.can_edit: + raise G3AuthError('You do not have permission to edit: %s' % + parent.title) + data = { + 'type': 'album' , + 'name': albumName , + 'title': title , + 'description': description , + } + req = PostRequest(parent.url , self.apiKey , data) + resp = self._openReq(req) + newObjUrl = self._getUrlFromResp(resp) + item = getItemFromResp(self.getRespFromUrl(newObjUrl) , self , parent) + parent._members.append(newObjUrl) + parent.members.append(item) + return item + + def addImage(self , parent , image , title='' , description='' , name=''): + """ + Add a LocalImage to the parent album. + + parent(Album) : The parent album to add the image to + image(LocalImage) : The local image to upload and add to the + parent + title(str) : The image title + description(str) : The image description + name(str) : The image file name + + returns(RemoteImage) : The RemoteImage instance for the item + uploaded + """ + if not parent.can_edit: + raise G3AuthError('You do not have permission to edit: %s' % + parent.title) + if name: + image.Filename = name + entity = { + 'name': image.filename , + 'type': image.type , + 'title': title , + 'description': description , + } + boundary = str(uuid4()) + headers = {'Content-Type': 'multipart/form-data; boundary=%s' % + boundary} + # this is more complicated than adding an album. We have to + # construct the upload MIME headers, including build the string + # data section + data = '--%s\r\n' % boundary + data += 'Content-Disposition: form-data; name="entity"\r\n' + data += 'Content-Type: text/plain; ' \ + 'charset=UTF-8\r\n' + data += 'Content-Transfer-Encoding: 8bit\r\n' + data += '\r\n' + data += '%s\r\n' % json.dumps(entity , separators=(',' , ':')) + data += '--%s\r\n' % boundary + data += image.getUploadContent() + data += '--%s--\r\n' % boundary + req = PostRequest(parent.url , self.apiKey , data , headers) + resp = self._openReq(req) + newObjUrl = self._getUrlFromResp(resp) + item = getItemFromResp(self.getRespFromUrl(newObjUrl) , self , parent) + parent._members.append(newObjUrl) + parent.members.append(item) + return item + + def addMovie(self , parent , movie , title='' , description='' , name=''): + """ + Add a LocalMovie to the parent album. + + parent(Album) : The parent album to add the movie to + image(LocalMovie) : The local movie to upload and add to the + parent + title(str) : The movie title + description(str) : The movie description + name(str) : The movie file name + + returns(RemoteMovie) : The RemoteMovie instance for the movie + uploaded + """ + return self.addImage(parent , movie , title , description , name) + + def setAlbumCover(self , album , image): + """ + Updates a remote item's title and description + + album(Album) : The album to set the cover on + image(RemoteImage) : The image to use as the cover + + returns(tuple(status , msg)) : Returns a tuple of a boolean status + and a message if there is an error + """ + if not album.can_edit: + raise G3AuthError('You do not have permission to edit: %s' % + album.title) + try: + self._isItemValid(album , Album) + self._isItemValid(image , RemoteImage) + except Exception , e: + return (False , str(e)) + data = { + 'album_cover': image.url , + } + req = PutRequest(album.url , self.apiKey , data) + try: + resp = self._openReq(req) + except G3RequestError , e: + return (False , str(e)) + album.album_cover = image + album._album_cover = image.url + return (True , '') + + def updateItem(self , item): + """ + Updates a remote item's title and description + + item(BaseRemote) : An item descended from BaseRemote + + returns(tuple(status , msg)) : Returns a tuple of a boolean status + and a message if there is an error + """ + if not item.can_edit: + raise G3AuthError('You do not have permission to edit: %s' % + item.title) + try: + self._isItemValid(item , BaseRemote) + except Exception , e: + return (False , str(e)) + data = { + 'title': item.title , + 'description': item.description , + } + req = PutRequest(item.url , self.apiKey , data) + try: + resp = self._openReq(req) + except G3RequestError , e: + return (False , str(e)) + return (True , '') + + def updateAlbum(self , album): + """ + Update the title and description for an album. + + image(Album) : Updates the title and/or description + for the Album + + returns(tuple(status , msg)) : Returns a tuple of a boolean status + and a message if there is an error + """ + return self.updateItem(album) + + def updateImage(self , image): + """ + Update the title and description for an image. + + image(RemoteImage) : Updates the title and/or description for the + RemoteImage + + returns(tuple(status , msg)) : Returns a tuple of a boolean status + and a message if there is an error + """ + return self.updateItem(image) + + def updateMovie(self , movie): + """ + Update the title and description for a movie. + + image(RemoteMovie) : Updates the title and/or description for the + RemoteMovie + + returns(tuple(status , msg)) : Returns a tuple of a boolean status + and a message if there is an error + """ + return self.updateItem(movie) + + def deleteItem(self , item): + """ + Deletes the given item. Item must be descended from BaseRemote. + + item(BaseRemote) : The item to delete + + returns(tuple(status , msg)) : Returns a tuple of a boolean status + and a message if there is an error + """ + if not item.can_edit: + raise G3AuthError('You do not have permission to edit: %s' % + item.title) + try: + self._isItemValid(item , BaseRemote) + except Exception , e: + return (False , e.message) + req = DeleteRequest(item.url , self.apiKey) + try: + resp = self._openReq(req) + except G3RequestError , e: + return (False , e.message) + return (True , '') + + def tagItem(self , item , tagName): + """ + Tag this item with the string "tagName" + + tagName(str) : The actual tag name + + returns(Tag) : The tag that was created + """ + # First we have to create the tag itself, if necessary + data = { + 'name': str(tagName) , + } + url = self._buildUrl('index.php/rest/tags') + req = PostRequest(url , self.apiKey , data) + resp = self._openReq(req) + r = json.loads(resp.read()) + tagUrl = r['url'] + # And now that we have our (possibly) newly created tag, we can + # use that to tag our item + data = { + 'tag': tagUrl , + 'item': item.url , + } + url = self._buildUrl('index.php/rest/item_tags/%s' % item.id) + req = PostRequest(url , self.apiKey , data) + resp = self._openReq(req) + respObj = json.loads(resp.read()) + item.relationships['tags']['members'].append(respObj['url']) + tag = Tag(respObj , self , item) + if hasattr(item , 'tags'): + item.tags.append(tag) + return tag + + def addComment(self , image , comment): + """ + Comment on this item with the string "comment" + + comment(str) : The comment + + returns(Comment) : The comment that was created + """ + data = { + 'item': image.url , + 'text': comment , + } + url = self._buildUrl('index.php/rest/comments') + req = PostRequest(url , self.apiKey , data) + resp = self._openReq(req) + commUrl = json.loads(resp.read())['url'] + resp = self.getRespFromUrl(commUrl) + comm = getItemFromResp(resp , self , image) + if hasattr(image , 'comments'): + image.comments.append(comm) + return comm + + def _buildOpener(self): + cp = urllib2.HTTPCookieProcessor() + self._opener = urllib2.build_opener(cp) + if self.ssl: + self._opener.add_handler(urllib2.HTTPSHandler()) + + def _buildUrl(self , resource , kwargs={}): + url = '%s://%s:%d/%s/%s' % (self.protocol , self.host , self.port , + quote(self.g3Base) , quote(resource)) + if kwargs: + url += '?%s' % urlencode(kwargs) + return url + + def _getUrlFromResp(self , resp): + d = json.loads(resp.read()) + return d['url'] + + def _openReq(self , req): + try: + resp = self._opener.open(req) + except urllib2.HTTPError , e: + err = json.loads(e.read()) + if isinstance(err , dict) and 'errors' in err: + raise G3RequestError(err['errors']) + else: + raise G3UnknownError('Unknown request error: %s' % e) + return resp + + def _isItemValid(self , item , cls): + if not isinstance(item , cls): + raise TypeError('Items to be modified must be descended from ' + '%s: %s' % (cls , type(item))) + if not 'url' in item.__dict__: + raise G3UnknownError('The object, %s, has no "url"' % item) + +def login(host , username , passwd , g3Base='/gallery3' , port=80 , + ssl=False): + """ + This will log you in and return a Gallery3 object on success, None + otherwise + + host(str) : The hostname of the gallery site + username(str) : The username to login with + passwd(str) : The password to login with + g3Base(str) : The remote url path to your gallery 3 install + (default: /gallery3) + port(int) : The port number to connect to (default: 80) + ssl(bool) : If true, use SSL for the connection (default: 80) + """ + data = { + 'user': username , + 'password': passwd , + } + protocol = ('http' , 'https')[ssl] + url = '%s://%s:%d/%s/index.php/rest' % (protocol , host , port , + quote(g3Base)) + req = PostRequest(url , None , urlencode(data)) + opener = urllib2.build_opener() + if ssl: + opener.add_handler(urllib2.HTTPSHandler()) + try: + resp = opener.open(req) + except urllib2.HTTPError , e: + return None + apiKey = resp.read().strip('\'"') + return Gallery3(host , apiKey , g3Base , port , ssl) diff --git a/3.0/client/Python/pylibgal3/libg3/Requests.py b/3.0/client/Python/pylibgal3/libg3/Requests.py new file mode 100644 index 00000000..7b0fedb6 --- /dev/null +++ b/3.0/client/Python/pylibgal3/libg3/Requests.py @@ -0,0 +1,72 @@ +# +# Author: Jay Deiman +# Email: admin@splitstreams.com +# +# This file is part of pylibgal3. +# +# pylibgal3 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pylibgal3 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pylibgal3. If not, see . +# + +__all__ = ['BaseRequest' , 'GetRequest' , 'PostRequest' , 'PutRequest' , + 'DeleteRequest'] + +from urllib2 import Request +from urllib import quote +import os , json , types + +class BaseRequest(Request): + def __init__(self , url , apiKey , data=None , headers={} , + origin_req_host=None , unverifiable=False): + if apiKey is not None: + headers['X-Gallery-Request-Key'] = apiKey + if data is not None: + if isinstance(data , dict): + data = 'entity=%s' % quote(json.dumps(data , + separators=(',' , ':'))) + elif type(data) not in types.StringTypes: + raise TypeError('Invalid type for data. It should be ' + 'a "dict" or "str", not %s' % type(data)) + headers['Content-Length'] = str(len(data)) + Request.__init__(self , url , data , headers , origin_req_host , + unverifiable) + +class GetRequest(BaseRequest): + def __init__(self , url , apiKey , data=None , headers={} , + origin_req_host=None , unverifiable=False): + headers['X-Gallery-Request-Method'] = 'get' + BaseRequest.__init__(self , url , apiKey , data , headers , + origin_req_host , unverifiable) + +class PostRequest(BaseRequest): + def __init__(self , url , apiKey , data , headers={} , + origin_req_host=None , unverifiable=False): + headers['X-Gallery-Request-Method'] = 'post' + if 'Content-Type' not in headers: + headers['Content-Type'] = 'application/x-www-form-urlencoded' + BaseRequest.__init__(self , url , apiKey , data , headers , + origin_req_host , unverifiable) + +class PutRequest(BaseRequest): + def __init__(self , url , apiKey , data=None , headers={} , + origin_req_host=None , unverifiable=False): + headers['X-Gallery-Request-Method'] = 'put' + BaseRequest.__init__(self , url , apiKey , data , headers , + origin_req_host , unverifiable) + +class DeleteRequest(BaseRequest): + def __init__(self , url , apiKey , data=None , headers={} , + origin_req_host=None , unverifiable=False): + headers['X-Gallery-Request-Method'] = 'delete' + BaseRequest.__init__(self , url , apiKey , data , headers , + origin_req_host , unverifiable) diff --git a/3.0/client/Python/pylibgal3/libg3/__init__.py b/3.0/client/Python/pylibgal3/libg3/__init__.py new file mode 100644 index 00000000..eec91668 --- /dev/null +++ b/3.0/client/Python/pylibgal3/libg3/__init__.py @@ -0,0 +1,24 @@ +# +# Author: Jay Deiman +# Email: admin@splitstreams.com +# +# This file is part of pylibgal3. +# +# pylibgal3 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pylibgal3 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pylibgal3. If not, see . +# + +from G3Items import * +from Gallery3 import * + +__version__ = '0.1.4' diff --git a/3.0/client/Python/pylibgal3/setup.py b/3.0/client/Python/pylibgal3/setup.py new file mode 100644 index 00000000..ba9d1d82 --- /dev/null +++ b/3.0/client/Python/pylibgal3/setup.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +# +# Author: Jay Deiman +# Email: admin@splitstreams.com +# +# This file is part of pylibgal3. +# +# pylibgal3 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pylibgal3 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pylibgal3. If not, see . +# + + +from distutils.core import setup +from libg3 import __version__ as version +import sys + +setup(name='pylibgal3' , + version=version , + author='Jay Deiman' , + author_email='admin@splitstreams.com' , + url='http://stuffivelearned.org' , + description='A library for accessing/manipulating a Gallery 3 install' , + packages=['libg3'] , + package_dir={'libg3': 'libg3'} , +) diff --git a/3.0/modules/about_this_album/helpers/about_this_album_block.php b/3.0/modules/about_this_album/helpers/about_this_album_block.php new file mode 100644 index 00000000..aefafff5 --- /dev/null +++ b/3.0/modules/about_this_album/helpers/about_this_album_block.php @@ -0,0 +1,76 @@ + t("About This Album")); + } + + static function get($block_id, $theme) { + switch ($block_id) { + case "aboutthisalbum": + $item = $theme->item; + if ((!$item) or (!$theme->item->is_album())) { + return ""; + } + if ($theme->item->is_album()) { + $block = new Block(); + $block->css_id = "g-about-this-album"; + $block->content = new View("about_this_album.html"); + + if ($theme->item()->id == item::root()->id) { + $block->title = t("About this Site"); + $block->content->album_count = ORM::factory("item")->where("type", "=", "album")->where("id", "<>", 1)->count_all(); + $block->content->photo_count = ORM::factory("item")->where("type", "=", "photo")->count_all(); + $block->content->vcount = Database::instance()->query("SELECT SUM({items}.view_count) as c FROM {items} WHERE type=\"photo\"")->current()->c; + } Else { + $block->title = t("About this Album"); + $block->content->album_count = $item->descendants_count(array(array("type", "=", "album"))); + $block->content->photo_count = $item->descendants_count(array(array("type", "=", "photo"))); + // $block->content->vcount= $theme->item()->view_count; + $descds = $item->descendants(); + $descds_view = 0; + foreach ($descds as $descd) { + if ($descd->is_photo()) { + $descds_view += $descd->view_count; + } + } + $block->content->vcount = $descds_view; + if ($item->description) { + $block->content->description = html::clean($item->description); + } + } + + + $all_tags = ORM::factory("tag") + ->join("items_tags", "items_tags.tag_id", "tags.id") + ->join("items", "items.id", "items_tags.item_id", "LEFT") + ->where("items.parent_id", "=", $item->id) + ->order_by("tags.id", "ASC") + ->find_all(); + if (count($all_tags) > 0) { + $block->content->all_tags = $all_tags; + } + } + break; + } + return $block; + } +} diff --git a/3.0/modules/about_this_album/module.info b/3.0/modules/about_this_album/module.info new file mode 100644 index 00000000..8080a24d --- /dev/null +++ b/3.0/modules/about_this_album/module.info @@ -0,0 +1,3 @@ +name = "About this Album" +description = "Show some simple, specific and useful info about a given album" +version = 1 diff --git a/3.0/modules/about_this_album/views/about_this_album.html.php b/3.0/modules/about_this_album/views/about_this_album.html.php new file mode 100644 index 00000000..01dee4f7 --- /dev/null +++ b/3.0/modules/about_this_album/views/about_this_album.html.php @@ -0,0 +1,68 @@ + + + diff --git a/3.0/modules/about_this_photo/helpers/about_this_photo_block.php b/3.0/modules/about_this_photo/helpers/about_this_photo_block.php new file mode 100644 index 00000000..267f3904 --- /dev/null +++ b/3.0/modules/about_this_photo/helpers/about_this_photo_block.php @@ -0,0 +1,71 @@ + t("About This Photo")); + } + + static function get($block_id, $theme) { + $block = new Block(); + switch ($block_id) { + case "simple": + $item = $theme->item; + if ((!$item) or (!$item->is_photo())) { + return ""; + } + $block->css_id = "g-about-this-photo"; + $block->title = t("About this photo"); + $block->content = new View("about_this_photo.html"); + + // exif API doesn't give easy access to individual keys, so do this the hard way + if (module::is_active("exif")) { + $exif = ORM::factory("exif_record")->where("item_id", "=", $theme->item()->id)->find(); + if ($exif->loaded()) { + $exif = unserialize($exif->data); + $timestamp = strtotime($exif["DateTime"]); + //$block->content->date = gallery::date($timestamp); + $block->content->date = date('D j M Y', $timestamp); + $block->content->time = gallery::time($timestamp); + } + } + + $block->content->vcount = $theme->item()->view_count; + + // IPTC - copied more or less from iptc.php + if (module::is_active("iptc")) { + $record = ORM::factory("iptc_record")->where("item_id", "=", $theme->item()->id)->find(); + if ($record->loaded()) { + $record = unserialize($record->data); + $block->content->name = $record["ObjectName"]; + $block->content->caption = $record["Caption"]; + + } + } + + if (module::is_active("tag")) { + $block->content->tags = tag::item_tags($theme->item()); + } + break; + } + return $block; + } +} + diff --git a/3.0/modules/about_this_photo/module.info b/3.0/modules/about_this_photo/module.info new file mode 100644 index 00000000..e324ae3b --- /dev/null +++ b/3.0/modules/about_this_photo/module.info @@ -0,0 +1,3 @@ +name = "About this Photo" +description = "Show some simple, specific and useful info about a given photo" +version = 3 diff --git a/3.0/modules/about_this_photo/views/about_this_photo.html.php b/3.0/modules/about_this_photo/views/about_this_photo.html.php new file mode 100644 index 00000000..f0ef130a --- /dev/null +++ b/3.0/modules/about_this_photo/views/about_this_photo.html.php @@ -0,0 +1,34 @@ + + + diff --git a/3.0/modules/adsense/controllers/admin_adsense.php b/3.0/modules/adsense/controllers/admin_adsense.php index 13be83d8..05f0c6ad 100644 --- a/3.0/modules/adsense/controllers/admin_adsense.php +++ b/3.0/modules/adsense/controllers/admin_adsense.php @@ -1,7 +1,7 @@ content = new View("admin_albumpassword.html"); + + // Generate a form for controlling the admin section. + $view->content->albumpassword_form = $this->_get_admin_form(); + + // Display the page. + print $view; + } + + private function _get_admin_form() { + // Make a new form for changing admin settings for this module. + $form = new Forge("admin/albumpassword/saveprefs", "", "post", + array("id" => "g-album-password-admin-form")); + + // Should protected items be hidden, or completely in-accessable? + $albumpassword_group = $form->group("album_password_group"); + $albumpassword_group->checkbox("hideonly") + ->label("Only hide protected albums?") + ->checked(module::get_var("albumpassword", "hideonly")); + + // Add a save button to the form. + $albumpassword_group->submit("save_settings")->value(t("Save")); + + // Return the newly generated form. + return $form; + } + + public function saveprefs() { + // Save user specified preferences. + + // Prevent Cross Site Request Forgery + access::verify_csrf(); + + // Retrieve submitted form data. + if (Input::instance()->post("hideonly") == false) { + module::set_var("albumpassword", "hideonly", false); + } else { + module::set_var("albumpassword", "hideonly", true); + } + // Display a success message and redirect back to the TagsMap admin page. + message::success(t("Your settings have been saved.")); + url::redirect("admin/albumpassword"); + } +} diff --git a/3.0/modules/albumpassword/controllers/albumpassword.php b/3.0/modules/albumpassword/controllers/albumpassword.php index b014b749..dfedcd2c 100644 --- a/3.0/modules/albumpassword/controllers/albumpassword.php +++ b/3.0/modules/albumpassword/controllers/albumpassword.php @@ -1,7 +1,7 @@ where("album_id", "=", $id)->find(); - if ($existing_password->loaded()) { + // Check for and delete the password and any cached ids assigned to it. + $existing_password = ORM::factory("items_albumpassword")->where("album_id", "=", $id)->find_all(); + if (count($existing_password) > 0) { + foreach ($existing_password as $one_password) { + db::build()->delete("albumpassword_idcaches")->where("password_id", "=", $one_password->id)->execute(); + } db::build()->delete("items_albumpasswords")->where("album_id", "=", $id)->execute(); message::success(t("Password Removed.")); } @@ -70,9 +73,12 @@ class albumpassword_Controller extends Controller { $album_id = Input::instance()->post("item_id"); $album_password = Input::instance()->post("assignpassword_password"); - // Check for, and remove, any existing passwords. - $existing_password = ORM::factory("items_albumpassword")->where("album_id", "=", $album_id)->find(); - if ($existing_password->loaded()) { + // Check for, and remove, any existing passwords and cached ids. + $existing_password = ORM::factory("items_albumpassword")->where("album_id", "=", $album_id)->find_all(); + if (count($existing_password) > 0) { + foreach ($existing_password as $one_password) { + db::build()->delete("albumpassword_idcaches")->where("password_id", "=", $one_password->id)->execute(); + } db::build()->delete("items_albumpasswords")->where("album_id", "=", $album_id)->execute(); } @@ -82,9 +88,28 @@ class albumpassword_Controller extends Controller { $new_password->password = $album_password; $new_password->save(); + // Add the album to the id cache. + $cached_album = ORM::factory("albumpassword_idcache"); + $cached_album->password_id = $new_password->id; + $cached_album->item_id = $album_id; + $cached_album->save(); + + // Check for any sub-items within the album, add all of them to the id cache. + $items = ORM::factory("item", $album_id) + ->viewable() + ->descendants(); + if (count($items) > 0) { + foreach ($items as $one_item) { + $cached_item = ORM::factory("albumpassword_idcache"); + $cached_item->password_id = $new_password->id; + $cached_item->item_id = $one_item->id; + $cached_item->save(); + } + } + // Display a success message and close the dialog. message::success(t("Password saved.")); - json::reply(array("result" => "success")); + print "\n\n\n\n\n"; } public function logout() { @@ -112,10 +137,10 @@ class albumpassword_Controller extends Controller { // If not, close the dialog and display a rejected message. cookie::set("g3_albumpassword", $album_password); message::success(t("Password Accepted.")); - json::reply(array("result" => "success")); + print "\n\n\n\n\n"; } else { message::error(t("Password Rejected.")); - json::reply(array("result" => "success")); + print "\n\n\n\n\n"; } } @@ -129,7 +154,7 @@ class albumpassword_Controller extends Controller { $assignpassword_group->input("assignpassword_password") ->id('assignpassword_password') ->label(t("Password:")); - $form->submit("save_password")->value(t("Save")); + $assignpassword_group->submit("save_password")->value(t("Save")); // Return the newly generated form. return $form; @@ -139,12 +164,14 @@ class albumpassword_Controller extends Controller { // Generate a form for allowing visitors to enter in their passwords. $form = new Forge("albumpassword/checkpassword", "", "post", array("id" => "g-login-password-form")); + $assignpassword_group = $form->group("Enter Password") ->label(t("Enter Password:")); - $assignpassword_group->input("albumpassword_password") + $assignpassword_group->password("albumpassword_password") ->id('albumpassword_password') ->label(t("Password:")); - $form->submit("login_password")->value(t("Login")); + + $assignpassword_group->submit("")->value(t("Login")); // Return the newly generated form. return $form; diff --git a/3.0/modules/albumpassword/helpers/MY_access.php b/3.0/modules/albumpassword/helpers/MY_access.php new file mode 100644 index 00000000..bda1db32 --- /dev/null +++ b/3.0/modules/albumpassword/helpers/MY_access.php @@ -0,0 +1,49 @@ +where("item_id", "=", $item->id)->order_by("cache_id")->find_all(); + if (count($item_protected) > 0) { + $existing_password = ORM::factory("items_albumpassword")->where("id", "=", $item_protected[0]->password_id)->find(); + if ($existing_password->loaded()) { + if ((cookie::get("g3_albumpassword") != $existing_password->password) && + (identity::active_user()->id != $item->owner_id) && + (!identity::active_user()->admin)) { + throw new Kohana_404_Exception(); + } + } + } + } + } +} diff --git a/3.0/modules/albumpassword/helpers/MY_item.php b/3.0/modules/albumpassword/helpers/MY_item.php index 3e09a64d..e26b65c6 100644 --- a/3.0/modules/albumpassword/helpers/MY_item.php +++ b/3.0/modules/albumpassword/helpers/MY_item.php @@ -1,7 +1,7 @@ where("id", "=", $model->id)->find(); - // Figure out if the user can access this album. - $deny_access = false; - $existing_password = ORM::factory("items_albumpassword")->where("album_id", "=", $model->id)->find(); - if ($existing_password->loaded()) { - if ((cookie::get("g3_albumpassword") != $existing_password->password) && - (identity::active_user()->id != $album_item->owner_id)) - $deny_access = true; - } + // If the user is an admin, don't hide anything anything. + // If not, hide whatever is restricted by an album password + // that the current user is not the owner of. + if (!identity::active_user()->admin) { - // set access::DENY if necessary. - if ($deny_access == true) { - $view_restrictions = array(); - if (!identity::active_user()->admin) { - foreach (identity::group_ids_for_active_user() as $id) { - $view_restrictions[] = array("items.view_$id", "=", access::DENY); + // Display items that are not in idcaches. + $model->and_open()->join("albumpassword_idcaches", "items.id", "albumpassword_idcaches.item_id", "LEFT OUTER") + ->and_where("albumpassword_idcaches.item_id", "IS", NULL); + + // ... Unless their password id corresponds with a valid password. + $existing_password = ORM::factory("items_albumpassword")->where("password", "=", cookie::get("g3_albumpassword"))->find_all(); + if (count($existing_password) > 0) { + foreach ($existing_password as $one_password) { + $model->or_where("albumpassword_idcaches.password_id", "=", $one_password->id); } } - } - if (count($view_restrictions)) { - $model->and_open()->merge_or_where($view_restrictions)->close(); + + // Or the current user is the owner of the item. + $model->or_where("items.owner_id", "=", identity::active_user()->id)->close(); } return $model; diff --git a/3.0/modules/albumpassword/helpers/albumpassword_event.php b/3.0/modules/albumpassword/helpers/albumpassword_event.php index dd83c4d9..0c9210ea 100644 --- a/3.0/modules/albumpassword/helpers/albumpassword_event.php +++ b/3.0/modules/albumpassword/helpers/albumpassword_event.php @@ -1,7 +1,7 @@ label(t("Remove password")) ->css_id("g-album-password-remove") ->url(url::site("albumpassword/remove/" . $item->id))); - } else { - $menu->get("options_menu") - ->append(Menu::factory("dialog") - ->id("albumpassword_assign") - ->label(t("Assign password")) - ->css_id("g-album-password-assign") - ->url(url::site("albumpassword/assign/" . $item->id))); + } elseif ($item->id != 1) { + $passworded_subitems = ORM::factory("item", $item->id) + ->and_open()->join("albumpassword_idcaches", "items.id", "albumpassword_idcaches.item_id", "LEFT OUTER") + ->where("albumpassword_idcaches.item_id", "IS NOT", NULL)->close() + ->descendants(); + + $existing_cacheditem = ORM::factory("albumpassword_idcache")->where("item_id", "=", $item->id)->order_by("cache_id")->find_all(); + if ((count($existing_cacheditem) == 0) && count($passworded_subitems) == 0) { + $menu->get("options_menu") + ->append(Menu::factory("dialog") + ->id("albumpassword_assign") + ->label(t("Assign password")) + ->css_id("g-album-password-assign") + ->url(url::site("albumpassword/assign/" . $item->id))); + } } } } } static function item_deleted($item) { - // If an album is deleted, remove any associated passwords. - $existingPasswords = ORM::factory("items_albumpassword") - ->where("album_id", "=", $item->id) - ->find_all(); - if (count($existingPasswords) > 0) { - db::build()->delete("items_albumpassword")->where("album_id", "=", $item->id)->execute(); + // Check for and delete the password and any cached ids assigned to it. + $existing_password = ORM::factory("items_albumpassword")->where("album_id", "=", $item->id)->find_all(); + if (count($existing_password) > 0) { + foreach ($existing_password as $one_password) { + db::build()->delete("albumpassword_idcaches")->where("password_id", "=", $one_password->id)->execute(); + } + db::build()->delete("items_albumpasswords")->where("album_id", "=", $item->id)->execute(); + message::success(t("Password Removed.")); + } else { + db::build()->delete("albumpassword_idcaches")->where("item_id", "=", $item->id)->execute(); } } + + static function item_created($item) { + // Check for any already existing password on parent album(s), if found, generate cache data for the new item. + $existing_password = ORM::factory("albumpassword_idcache")->where("item_id", "=", $item->parent_id)->order_by("cache_id")->find_all(); + if (count($existing_password) > 0) { + $new_cachedid = ORM::factory("albumpassword_idcache"); + $new_cachedid->password_id = $existing_password[0]->password_id; + $new_cachedid->item_id = $item->id; + $new_cachedid->save(); + } + } + + static function item_moved($item, $old_parent) { + // Delete any existing cache data. + db::build()->delete("albumpassword_idcaches")->where("item_id", "=", $item->id)->execute(); + + // Check for a password on the new parent, generate cache data if necessary. + $existing_password = ORM::factory("albumpassword_idcache")->where("item_id", "=", $item->parent_id)->order_by("cache_id")->find_all(); + if (count($existing_password) > 0) { + $new_cachedid = ORM::factory("albumpassword_idcache"); + $new_cachedid->password_id = $existing_password[0]->password_id; + $new_cachedid->item_id = $item->id; + $new_cachedid->save(); + } + } + + static function admin_menu($menu, $theme) { + // Add a link to the Album Password admin page to the Content menu. + $menu->get("settings_menu") + ->append(Menu::factory("link") + ->id("albumpassword") + ->label(t("Album Password Settings")) + ->url(url::site("admin/albumpassword"))); + } } diff --git a/3.0/modules/albumpassword/helpers/albumpassword_installer.php b/3.0/modules/albumpassword/helpers/albumpassword_installer.php index e59faffb..93a6d0c0 100644 --- a/3.0/modules/albumpassword/helpers/albumpassword_installer.php +++ b/3.0/modules/albumpassword/helpers/albumpassword_installer.php @@ -1,7 +1,7 @@ query("CREATE TABLE IF NOT EXISTS {albumpassword_idcaches} ( + `cache_id` int(9) NOT NULL auto_increment, + `password_id` int(9) NOT NULL, + `item_id` int(9) NOT NULL, + PRIMARY KEY (`cache_id`)) + DEFAULT CHARSET=utf8;"); + + // Set the default value for this module's behavior. + module::set_var("albumpassword", "hideonly", true); // Set the module's version number. - module::set_version("albumpassword", 1); + module::set_version("albumpassword", 3); + } + + static function upgrade($version) { + $db = Database::instance(); + if ($version == 1) { + // Set the default value for this module's behavior. + module::set_var("albumpassword", "hideonly", true); + module::set_version("albumpassword", $version = 2); + } + if ($version == 2) { + // Create a table to store a list of all protected items in. + $db->query("CREATE TABLE IF NOT EXISTS {albumpassword_idcaches} ( + `cache_id` int(9) NOT NULL auto_increment, + `password_id` int(9) NOT NULL, + `item_id` int(9) NOT NULL, + PRIMARY KEY (`cache_id`)) + DEFAULT CHARSET=utf8;"); + module::set_version("albumpassword", $version = 3); + } } static function uninstall() { // Delete the password table before uninstalling. $db = Database::instance(); - $db->query("DROP TABLE IF EXISTS {items_albumpassword};"); + $db->query("DROP TABLE IF EXISTS {items_albumpasswords};"); + $db->query("DROP TABLE IF EXISTS {albumpassword_idcaches};"); module::delete("albumpassword"); } } diff --git a/3.0/modules/albumpassword/helpers/albumpassword_task.php b/3.0/modules/albumpassword/helpers/albumpassword_task.php new file mode 100644 index 00000000..b6ea007a --- /dev/null +++ b/3.0/modules/albumpassword/helpers/albumpassword_task.php @@ -0,0 +1,138 @@ +join("albumpassword_idcaches", "items_albumpasswords.id", "albumpassword_idcaches.password_id", "LEFT OUTER") + ->and_where("albumpassword_idcaches.password_id", "IS", NULL)->count_all(); + + return array(Task_Definition::factory() + ->callback("albumpassword_task::update_idcaches") + ->name(t("Rebuild Album Password ID Caches DB")) + ->description(t("Logs the contents of all protected albums into the db.")) + ->severity($bad_albums ? log::WARNING : log::SUCCESS)); + } + + static function update_idcaches($task) { + // Populate the idcaches table with the contents of all protected albums. + + $start = microtime(true); + $total = $task->get("total"); + $existing_passwords = ORM::factory("items_albumpassword")->find_all(); + // If this is the first time this function has been run, + // delete and re-create the idcaches table, and set up + // some initial variables. + if (empty($total)) { + // Delete the idcache table and make a new one. + $db = Database::instance(); + $db->query("DROP TABLE IF EXISTS {albumpassword_idcaches};"); + $db->query("CREATE TABLE IF NOT EXISTS {albumpassword_idcaches} ( + `cache_id` int(9) NOT NULL auto_increment, + `password_id` int(9) NOT NULL, + `item_id` int(9) NOT NULL, + PRIMARY KEY (`cache_id`)) + DEFAULT CHARSET=utf8;"); + + // Set the initial values for all variables. + $task->set("total", count($existing_passwords)); + $total = $task->get("total"); + $task->set("last_album_counter", 0); + $task->set("last_id", 0); + $task->set("completed_albums", 0); + $task->set("completed_items", 0); + $task->set("total_items", 0); + } + + // Retrieve the values for variables from the last time this + // function was run. + $last_album_counter = $task->get("last_album_counter"); + $completed_albums = $task->get("completed_albums"); + $completed_items = $task->get("completed_items"); + $total_items = $task->get("total_items"); + $last_id = $task->get("last_id"); + + // If completed_items is 0, then we're just starting to process this + // album. Add the album to idcaches before adding it's contents. + if ($completed_items == 0) { + // Add the album to the id cache. + $cached_album = ORM::factory("albumpassword_idcache"); + $cached_album->password_id = $existing_passwords[$last_album_counter]->id; + $cached_album->item_id = $existing_passwords[$last_album_counter]->album_id; + $cached_album->save(); + + // Set total_items to the number of items in this album. + $total_items = ORM::factory("item", $existing_passwords[$last_album_counter]->album_id) + ->descendants_count(); + $task->set("total_items", $total_items); + } + + // Add each item in the album to idcaches. + foreach (ORM::factory("item", $existing_passwords[$last_album_counter]->album_id) + ->where("id", ">", $last_id) + ->order_by("id") + ->descendants(100) as $item) { + + $cached_item = ORM::factory("albumpassword_idcache"); + $cached_item->password_id =$existing_passwords[$last_album_counter]->id; + $cached_item->item_id = $item->id; + $cached_item->save(); + + $last_id = $item->id; + $completed_items++; + + // Set a time limit so the script doesn't time out. + if (microtime(true) - $start > 1.5) { + break; + } + } // end foreach + + // If completed_items equals total_items, then we've + // processed everything in the current album. + // Increase variables and set everything up for the + // next album. + if ($completed_items == $total_items) { + $completed_items = 0; + $last_album_counter++; + $completed_albums++; + $last_id = 0; + } + + // Store the current values of the variables for the next + // time this function is called. + $task->set("last_album_counter", $last_album_counter); + $task->set("last_id", $last_id); + $task->set("completed_albums", $completed_albums); + $task->set("completed_items", $completed_items); + + // Display the number of albums that have been completed before exiting. + if ($total == $completed_albums) { + $task->done = true; + $task->state = "success"; + $task->percent_complete = 100; + $task->status = t("Scanning Protected Album $completed_albums of $total"); + } else { + $task->percent_complete = round(100 * $completed / $total); + $task->status = t("Scanning Protected Album $completed_albums of $total -- $completed_items / $total_items files"); + } + } +} diff --git a/3.0/modules/albumpassword/models/albumpassword_idcache.php b/3.0/modules/albumpassword/models/albumpassword_idcache.php new file mode 100644 index 00000000..e3d80667 --- /dev/null +++ b/3.0/modules/albumpassword/models/albumpassword_idcache.php @@ -0,0 +1,21 @@ + +

+ +

+
+
+

+ +
diff --git a/3.0/modules/albumpassword/views/assignpassword.html.php b/3.0/modules/albumpassword/views/assignpassword.html.php index 14cd2767..c1a60b8d 100644 --- a/3.0/modules/albumpassword/views/assignpassword.html.php +++ b/3.0/modules/albumpassword/views/assignpassword.html.php @@ -1,20 +1,3 @@ -
  • diff --git a/3.0/modules/albumpassword/views/loginpassword.html.php b/3.0/modules/albumpassword/views/loginpassword.html.php index 9ebb47fd..750ffbed 100644 --- a/3.0/modules/albumpassword/views/loginpassword.html.php +++ b/3.0/modules/albumpassword/views/loginpassword.html.php @@ -1,20 +1,3 @@ -
    • diff --git a/3.0/modules/albumtree/helpers/albumtree_block.php b/3.0/modules/albumtree/helpers/albumtree_block.php new file mode 100644 index 00000000..f812ab17 --- /dev/null +++ b/3.0/modules/albumtree/helpers/albumtree_block.php @@ -0,0 +1,38 @@ + t("Album tree")); + } + + static function get($block_id) { + $block = new Block(); + switch ($block_id) { + case "albumtree": + $style = module::get_var("albumtree", "style", "select"); + $block->css_id = "g-albumtree"; + $block->title = t("Album Tree"); + $block->content = new View("albumtree_block_{$style}.html"); + $block->content->root = item::root(); + break; + } + return $block; + } +} \ No newline at end of file diff --git a/3.0/modules/albumtree/helpers/albumtree_installer.php b/3.0/modules/albumtree/helpers/albumtree_installer.php new file mode 100644 index 00000000..592a9b71 --- /dev/null +++ b/3.0/modules/albumtree/helpers/albumtree_installer.php @@ -0,0 +1,33 @@ + + + + + + diff --git a/3.0/modules/albumtree/views/albumtree_block_select.html.php b/3.0/modules/albumtree/views/albumtree_block_select.html.php new file mode 100644 index 00000000..4a73c333 --- /dev/null +++ b/3.0/modules/albumtree/views/albumtree_block_select.html.php @@ -0,0 +1,24 @@ + + diff --git a/3.0/modules/atom/module.info b/3.0/modules/atom/module.info new file mode 100644 index 00000000..e9d35a69 --- /dev/null +++ b/3.0/modules/atom/module.info @@ -0,0 +1,3 @@ +name = "Atom" +description = "Enable Atom feeds in your Gallery" +version = 1 diff --git a/3.0/modules/author/helpers/author.php b/3.0/modules/author/helpers/author.php new file mode 100644 index 00000000..ae259ec8 --- /dev/null +++ b/3.0/modules/author/helpers/author.php @@ -0,0 +1,121 @@ +is_album()) { return false; } + + $mime = $item->mime_type; + if ($mime == 'image/jpeg' || $mime == 'image/png' || $mime == 'image/gif') {} + else { return false; } + + $owner = ORM::factory("user")->where("id", "=", $item->owner_id)->find(); + $user_name = $owner->full_name; + + $exiv = module::get_var('author', 'exiv_path'); + $version = module::get_var('author', 'exiv_version'); + + /* + Debian stable ships with exiv2 0.16 at the time of writing. You get + roughly the same output out of the utility as with 0.20, but you have + to invoke it several times. + + The real threshhold for this might be somewhere between 0.16 and 0.20, + but the 0.16 way of doing things is forward compatible. + */ + $exivData = array(); + if ($version < 0.20) { + exec("$exiv -p x " . escapeshellarg($item->file_path()), $exivData); + exec("$exiv -p i " . escapeshellarg($item->file_path()), $exivData); + exec("$exiv -p t " . escapeshellarg($item->file_path()), $exivData); + } else { + exec("$exiv -p a " . escapeshellarg($item->file_path()), $exivData); + } + + $has = array(); + $mod = array(); + foreach ($exivData as $line) + { + $tokens = preg_split('/\s+/', $line, 4); + $has[ $tokens[0] ] = $tokens[3]; + } + + $candidates = array( + $has['Xmp.dc.creator'], + $has['Iptc.Application2.Byline'], + $has['Exif.Image.Artist'], + $user_name, + 'Unknown'); + + foreach ($candidates as $cand) { + if ($cand != '') { $byline = $cand; break; } + } + + if (!array_key_exists('Exif.Image.Artist', $has)) { $mod['Exif.Image.Artist'] = $byline; } + if (!array_key_exists('Iptc.Application2.Byline', $has)) { $mod['Iptc.Application2.Byline'] = $byline; } + + /* Apply the credit block */ + $credit = module::get_var("author", "credit"); + if ($credit != '') { + $mod['Iptc.Application2.Credit'] = $credit; + } + + /* + Older versions doesn't support XMP writing. + */ + if ($version >= 0.20) { + if (!array_key_exists('Xmp.dc.creator', $has)) { $mod['Xmp.dc.creator'] = $byline; } + + /* Apply our own image terms URL */ + $terms = module::get_var("author", "usage_terms"); + if ($terms != '') { + $mod['Xmp.xmpRights.UsageTerms'] = 'http://wiki.sverok.se/wiki/Bildbank-Bilder'; + } + } + + $line = $exiv . ' '; + foreach ($mod as $key => $value) { + $line .= "-M \"set $key " . escapeshellarg($value) . "\" "; + } + + $files = array( + $item->file_path(), + $item->thumb_path(), + $item->resize_path() + ); + + foreach ($files as $file) { + system("$line " . escapeshellarg($file)); + } + + $record = ORM::factory("author_record")->where("item_id", "=", $item->id)->find(); + if (!$record->loaded()) { + $record->item_id = $item->id; + } + $record->author = $byline; + $record->dirty = 0; + $record->save(); + return $byline; + } + +} diff --git a/3.0/modules/author/helpers/author_block.php b/3.0/modules/author/helpers/author_block.php new file mode 100644 index 00000000..9b571ba3 --- /dev/null +++ b/3.0/modules/author/helpers/author_block.php @@ -0,0 +1,48 @@ + t("Author")); + } + + static function get($block_id, $theme) { + $item = $theme->item; + if ($block_id != 'author' || $item->is_album() ) { + return ''; + } + $record = db::build() + ->select("author") + ->from("author_records") + ->where("item_id", "=", $item->id) + ->execute() + ->current(); + + $byline = $record->author; + if ($byline == '') { + $byline = author::fix($item); + } + + $block = new Block(); + $block->content = new View("author_block.html"); + $block->content->author = $byline; + + return $block; + } +} diff --git a/3.0/modules/author/helpers/author_event.php b/3.0/modules/author/helpers/author_event.php new file mode 100644 index 00000000..b9c31c8c --- /dev/null +++ b/3.0/modules/author/helpers/author_event.php @@ -0,0 +1,32 @@ +delete("author_records") + ->where("item_id", "=", $item->id) + ->execute(); + } +} diff --git a/3.0/modules/author/helpers/author_installer.php b/3.0/modules/author/helpers/author_installer.php new file mode 100644 index 00000000..1186f1f0 --- /dev/null +++ b/3.0/modules/author/helpers/author_installer.php @@ -0,0 +1,64 @@ +query("CREATE TABLE IF NOT EXISTS {author_records} ( + `id` int(9) NOT NULL auto_increment, + `item_id` INTEGER(9) NOT NULL, + `author` TEXT, + `dirty` BOOLEAN default 1, + PRIMARY KEY (`id`), + KEY(`item_id`)) + DEFAULT CHARSET=utf8;"); + module::set_version("author", 1); + module::set_var("author", "usage_terms", ''); + module::set_var("author", "credit", ''); + + return true; + } + + static function activate() { + gallery::set_path_env( + array( + getenv("PATH"), + module::get_var("gallery", "extra_binary_paths") + )); + + $exiv = exec('which exiv2'); + if ($exiv == '') { + # Proper warning + } + else { + module::set_var("author", "exiv_path", $exiv); + $out = array(); + exec("$exiv -V", $out); + $parts = split(' ', $out[0]); + module::set_var("author", "exiv_version", $parts[1]); + } + } + + static function deactivate() { + } + + static function uninstall() { + Database::instance()->query("DROP TABLE IF EXISTS {author_records};"); + } +} diff --git a/3.0/modules/author/models/author_record.php b/3.0/modules/author/models/author_record.php new file mode 100644 index 00000000..bd6eeb03 --- /dev/null +++ b/3.0/modules/author/models/author_record.php @@ -0,0 +1,21 @@ + + +
      +: +
      + diff --git a/3.0/modules/autorotate/helpers/autorotate.php b/3.0/modules/autorotate/helpers/autorotate.php index 5bfe1afe..bf531d01 100644 --- a/3.0/modules/autorotate/helpers/autorotate.php +++ b/3.0/modules/autorotate/helpers/autorotate.php @@ -1,7 +1,7 @@ _get_s3_form(); + + if (request::method() == "post") { + access::verify_csrf(); + + if (($valid_form = $form->validate()) && + ($s3_axs_correct = aws_s3::validate_access_details($_POST['access_key'], $_POST['secret_key'], $_POST['bucket_name']))) { + + // get variable values before changes so we can act on certain changes later + $vars = array(); + foreach (ORM::factory("var")->where("module_name", "=", "aws_s3")->find_all() as $var) { + $vars[$var->name] = $var->value; + } + + // set variables from $_POST into module::set_var() to save + module::set_var("aws_s3", "enabled", (isset($_POST['enabled']) ? true : false)); + module::set_var("aws_s3", "access_key", $_POST['access_key']); + module::set_var("aws_s3", "secret_key", $_POST['secret_key']); + module::set_var("aws_s3", "bucket_name", $_POST['bucket_name']); + site_status::clear("aws_s3_not_configured"); + + module::set_var("aws_s3", "g3id", $_POST['g3id']); + + module::set_var("aws_s3", "url_str", $_POST['url_str']); + module::set_var("aws_s3", "sig_exp", $_POST['sig_exp']); + + module::set_var("aws_s3", "use_ssl", (isset($_POST['use_ssl']) ? true : false)); + + module::set_var("aws_s3", "upload_thumbs", (isset($_POST['upload_thumbs']) ? true : false)); + module::set_var("aws_s3", "upload_resizes", (isset($_POST['upload_resizes']) ? true : false)); + module::set_var("aws_s3", "upload_fullsizes", (isset($_POST['upload_fullsizes']) ? true : false)); + + module::set_var("aws_s3", "s3_storage_only", (isset($_POST['s3_storage_only']) ? true : false)); + + // post option processing +// if (module::get_var("aws_s3", "s3_storage_only") && !module::get_var("aws_s3", "enabled")) { +// module::set_var("aws_s3", "enabled", true); +// module::set_var("aws_s3", "upload_thumbs", true); +// module::set_var("aws_s3", "upload_resizes", true); +// module::set_var("aws_s3", "upload_fullsizes", true); +// } +// if (module::get_var("aws_s3", "s3_storage_only") && !$vars['s3_storage_only']) { +// // content needs remove from local storage as it wasn't switched on before this point. +// if (!module::get_var("aws_s3", "synced")) { +// // force a sync between local storage and S3, as we're about to remove content from local storage. +// } +// } +// else if (!module::get_var("aws_s3", "s3_storage_only") && $vars['s3_storage_only']) { +// // content needs to be downloaded from s3 as it was just switched off. at this point, +// // we shouldn't actually have a copy of the gallery content locally. +// } + + if (module::get_var("aws_s3", "enabled") && !module::get_var("aws_s3", "synced", false)) { + if (aws_s3::can_schedule()) { + // i can schedule this task + aws_s3::schedule_full_sync2(); + site_status::warning( + "Your site has been scheduled for full Amazon S3 re-synchronisation. This message will clear when this has been completed.", + "aws_s3_not_synced" + ); + } + else { + // i CAN'T schedule it.. + site_status::warning( + t('Your site has not been synchronised to Amazon S3. Until it has, your server will continue to serve image content to your visitors. Click
      here to start the synchronisation task.', + array("url" => html::mark_clean(url::site("admin/maintenance/start/aws_s3_task::manual_sync?csrf=__CSRF__"))) + ), + "aws_s3_not_synced" + ); + } + } + + message::success(t("Settings have been saved")); + url::redirect("admin/aws_s3"); + } + else { + if (!$valid_form) + message::error(t("There was a problem with the submitted form. Please check your values and try again.")); + if (!$s3_axs_correct) { + message::error(t("The Amazon S3 access details provided appear to be incorrect. Please check your values and try again.")); + $form->aws_s3->access_key->add_error("invalid", true); + $form->aws_s3->secret_key->add_error("invalid", true); + $form->aws_s3->bucket_name->add_error("invalid", true); + } + } + } + + $v = new Admin_View("admin.html"); + $v->page_title = t("Amazon S3 Configuration"); + $v->content = new View("admin_aws_s3.html"); + $v->content->form = $form; + $v->content->end = ""; + + echo $v; + } + + private function _get_s3_form() { + $form = new Forge("admin/aws_s3", "", "post", array("id" => "g-admin-s3-form")); + + $group = $form->group("aws_s3")->label(t("Amazon S3 Settings")); + + $chkbox = + $group ->checkbox("enabled") + ->id("s3-enabled") + ->checked(module::get_var("aws_s3", "enabled", true)) + ->label("S3 enabled"); + + if (module::get_var("aws_s3", "s3_storage_only")) + $chkbox->disabled(true) + ->message("Warning:You may not turn this option off as S3 Storage Only is enabled. In order to disable using S3, you must first disable S3 Storage Only to re-download your content from Amazon S3, since it does not yet exist on the local server."); + + $group ->input("access_key") + ->id("s3-access-key") + ->label("Access Key ID") + ->value(module::get_var("aws_s3", "access_key")) + ->rules("required") + ->error_messages("required", "This field is required") + ->error_messages("invalid", "Access Key is invalid") + ->message('Click here to sign up to Amazon Web Services.'); + + $group ->input("secret_key") + ->id("s3-secret-key") + ->label("Secret Access Key") + ->value(module::get_var("aws_s3", "secret_key")) + ->rules("required") + ->error_messages("required", "This field is required") + ->error_messages("invalid", "Secret Key is invalid"); + + $group ->input("bucket_name") + ->id("s3-bucket") + ->label("Bucket Name") + ->value(module::get_var("aws_s3", "bucket_name")) + ->rules("required") + ->callback("aws_s3::validate_bucket") + ->error_messages("required", "This field is required") + ->error_messages("invalid", "Bucket name is invalid") + ->message('Note: This module will not create a bucket if it does not already exist. Please ensure you have already created the bucket using the AWS Console before continuing.
      +Click here for information on Amazon S3 bucket naming conventions/restrictions.'); + + $group ->input("g3id") + ->id("s3-g3id") + ->label("G3 ID") + ->value(module::get_var("aws_s3", "g3id", md5(time()))) + ->rules("required") + ->error_messages("required", "This field is required") + ->message("Utilising this field allows for multiple G3 file repositories stored inside the same S3 bucket."); + + $group ->checkbox("use_ssl") + ->id("s3-use-ssl") + ->checked(module::get_var("aws_s3", "use_ssl")) + ->label("Use SSL for S3 transfers") + ->message("You may have problems when uploading content to S3 if this option is enabled. If so, turn off this option."); + + $group = $form->group("cdn_settings")->label(t("CDN Settings")); + + $group ->input("url_str") + ->id("s3-url-str") + ->label("URL String") + ->value(module::get_var("aws_s3", "url_str", "http://{bucket}.s3.amazonaws.com/g3/{guid}/{resource}")) + ->rules("required") + ->message("Configure the URL to access uploaded resources on the CDN. Use the following variables to define and build up the URL:
      +• {bucket} - Bucket Name
      +• {guid} - Unique identifier for this gallery installation
      +• {resource} - The end path to the resource/object"); + + $group ->input("sig_exp") + ->id("s3-sig_exp") + ->label("Private Content Signature Duration") + ->value(module::get_var("aws_s3", "sig_exp", 60)) + ->rules("required") + ->callback("aws_s3::validate_number") + ->error_messages("not_numeric", "The value provided is not numeric. Please enter a number in this field.") + ->message("Set the time in seconds until the generated signature expires access to permission-restricted S3 objects (private content on G3 is where the user group 'Everybody' does not have access).

      +Note: this module does not yet support the creation of signatures to access private objects on S3 via CloudFront CDN."); + + $group = $form->group("general_settings")->label(t("General Settings")); + + $chkbox = + $group ->checkbox("upload_thumbs") + ->id("s3-upload_thumbs") + ->label("Upload Thumbnails") + ->checked(module::get_var("aws_s3", "upload_thumbs", true)); + if (module::get_var("aws_s3", "s3_storage_only")) + $chkbox->disabled(true); + + $chkbox = + $group ->checkbox("upload_resizes") + ->id("s3-upload_resizes") + ->label("Upload Resized Images") + ->checked(module::get_var("aws_s3", "upload_resizes", true)); + if (module::get_var("aws_s3", "s3_storage_only")) + $chkbox->disabled(true); + + $chkbox = + $group ->checkbox("upload_fullsizes") + ->id("s3-upload_fullsizes") + ->label("Upload Fullsize Images") + ->checked(module::get_var("aws_s3", "upload_fullsizes", true)); + if (module::get_var("aws_s3", "s3_storage_only")) + $chkbox->disabled(true); + + $chkbox = + $group ->checkbox("s3_storage_only") + ->id("s3-storage-only") + ->label("Use S3 for primary storage of Gallery content (Not yet available)") + ->checked(module::get_var("aws_s3", "s3_storage_only", false)) + ->message("Use this option if your webhost has limited space available on your account. This module will remove content from the local server after it has been uploaded to S3.

      +Note: You must have enough storage on your webhost account to store the images temporarily until they have been uploaded to S3.
      ") + ->disabled(true); + + if (!module::get_var("aws_s3", "enabled")) + $chkbox->disabled(true); + + // done creating form. + $form ->submit("save") + ->value("Save Settings"); + + + return $form; + } + +} \ No newline at end of file diff --git a/3.0/modules/aws_s3/controllers/aws_s3.php b/3.0/modules/aws_s3/controllers/aws_s3.php new file mode 100644 index 00000000..a5d092b2 --- /dev/null +++ b/3.0/modules/aws_s3/controllers/aws_s3.php @@ -0,0 +1,9 @@ +item && $theme->item->view_1 == 1) + parent::get($block_id, $theme); + } + +} \ No newline at end of file diff --git a/3.0/modules/aws_s3/helpers/MY_embedlinks_theme.php b/3.0/modules/aws_s3/helpers/MY_embedlinks_theme.php new file mode 100644 index 00000000..87434ca8 --- /dev/null +++ b/3.0/modules/aws_s3/helpers/MY_embedlinks_theme.php @@ -0,0 +1,31 @@ +item; + if ($item->view_1 == 1) + return parent::photo_bottom($theme); + } + } + +} \ No newline at end of file diff --git a/3.0/modules/aws_s3/helpers/MY_item.php b/3.0/modules/aws_s3/helpers/MY_item.php new file mode 100644 index 00000000..e7031c27 --- /dev/null +++ b/3.0/modules/aws_s3/helpers/MY_item.php @@ -0,0 +1,41 @@ +parent(); + if ($parent->id > 1) { + aws_s3::upload_item($parent); + } + } + + static function remove_album_cover($album) { + parent::remove_album_cover($album); + + if ($album->id > 1) { + aws_s3::remove_item($album); + } + } + +} \ No newline at end of file diff --git a/3.0/modules/aws_s3/helpers/aws_s3.php b/3.0/modules/aws_s3/helpers/aws_s3.php new file mode 100644 index 00000000..eafdaf62 --- /dev/null +++ b/3.0/modules/aws_s3/helpers/aws_s3.php @@ -0,0 +1,330 @@ + 0) + return $matches[1]; + return false; + } + + static function log($item) { + if (is_string($item) || is_numeric($item)) {} + else + $item = print_r($item, true); + + $fh = fopen(VARPATH . "modules/aws_s3/log/aws_s3-" . date("Y-m-d") . ".log", "a"); + fwrite($fh, date("Y-m-d H:i:s") . ": " . $item . "\n"); + fclose($fh); + } + + static function get_upload_flags() { + $flags = 0; + if (module::get_var("aws_s3", "upload_thumbs") == 1) + $flags += self::UPLOAD_THUMB; + if (module::get_var("aws_s3", "upload_resizes") == 1) + $flags += self::UPLOAD_RESIZE; + if (module::get_var("aws_s3", "upload_fullsizes") == 1) + $flags += self::UPLOAD_FULLSIZE; + return $flags; + } + + static function upload_item($item, $flags = 7) { + self::get_s3(); + + $filename = urldecode($item->relative_path()); + $itype = "I"; + if ($item->is_album()) { + $filename .= "/.album.jpg"; + $itype = "A"; + } + + if (!$item->s3_fullsize_uploaded && $flags & aws_s3::UPLOAD_FULLSIZE && !$item->is_album()) { + aws_s3::log("[" . $itype . ":" . $item->id . "] Uploading fullsize object"); + $success_fs = S3::putObjectFile(VARPATH . "albums/" . $filename, + module::get_var("aws_s3", "bucket_name"), + self::get_resource_url("fs/" . $filename), + ($item->view_1 ? S3::ACL_PUBLIC_READ : S3::ACL_PRIVATE)); + $item->s3_fullsize_uploaded = $success_fs; + } + else + $success_fs = true; + + if (!$item->s3_resize_uploaded && $flags & aws_s3::UPLOAD_RESIZE && !$item->is_album()) { + aws_s3::log("[" . $itype . ":" . $item->id . "] Uploading resize object"); + $success_rs = S3::putObjectFile(VARPATH . "resizes/" . $filename, + module::get_var("aws_s3", "bucket_name"), + self::get_resource_url("rs/" . $filename), + ($item->view_1 ? S3::ACL_PUBLIC_READ : S3::ACL_PRIVATE)); + $item->s3_resize_uploaded = $success_rs; + } + else + $success_rs = true; + + if (!$item->s3_thumb_uploaded && $flags & aws_s3::UPLOAD_THUMB) { + aws_s3::log("[" . $itype . ":" . $item->id . "] Uploading thumbnail object"); + $success_th = S3::putObjectFile(VARPATH . "thumbs/" . $filename, + module::get_var("aws_s3", "bucket_name"), + self::get_resource_url("th/" . $filename), + ($item->view_1 ? S3::ACL_PUBLIC_READ : S3::ACL_PRIVATE)); + $item->s3_thumb_uploaded = $success_th; + } + else + $success_th = true; + + $item->s3_item_hash = md5($item->relative_path()); + + $item->save(); + + $success = $success_fs && $success_th && $success_rs; + aws_s3::log("item upload success: " . $success); + return $success; + } + + static function move_item($old_item, $new_item) { + self::get_s3(); + + $old_filename = urldecode($old_item->relative_path()); + $new_filename = urldecode($new_item->relative_path()); + + aws_s3::log("old filename: " . self::get_resource_url("fs/" . $old_filename) . ", " . + "new filename: " . self::get_resource_url("fs/" . $new_filename)); + + //aws_s3::log($old_item->get_aws_s3_meta()); + + if ($old_item->s3_fullsize_uploaded) { + aws_s3::log("Copying fullsize " . $old_filename . " to " . $new_filename); + S3::copyObject(module::get_var("aws_s3", "bucket_name"), self::get_resource_url("fs/" . $old_filename), + module::get_var("aws_s3", "bucket_name"), self::get_resource_url("fs/" . $new_filename), + ($new_item->view_1 ? S3::ACL_PUBLIC_READ : S3::ACL_PRIVATE)); + S3::deleteObject(module::get_var("aws_s3", "bucket_name"), self::get_resource_url("fs/" . $old_filename)); + } + else + aws_s3::upload_item($new_item, aws_s3::UPLOAD_FULLSIZE); + + if ($old_item->s3_resize_uploaded) { + aws_s3::log("Copying resized " . $old_filename . " to " . $new_filename); + S3::copyObject(module::get_var("aws_s3", "bucket_name"), self::get_resource_url("rs/" . $old_filename), + module::get_var("aws_s3", "bucket_name"), self::get_resource_url("rs/" . $new_filename), + ($new_item->view_1 ? S3::ACL_PUBLIC_READ : S3::ACL_PRIVATE)); + S3::deleteObject(module::get_var("aws_s3", "bucket_name"), self::get_resource_url("rs/" . $old_filename)); + } + else + aws_s3::upload_item($new_item, aws_s3::UPLOAD_RESIZE); + + if ($old_item->s3_thumb_uploaded) { + aws_s3::log("Copying thumbnail " . $old_filename . " to " . $new_filename); + S3::copyObject(module::get_var("aws_s3", "bucket_name"), self::get_resource_url("th/" . $old_filename), + module::get_var("aws_s3", "bucket_name"), self::get_resource_url("th/" . $new_filename), + ($new_item->view_1 ? S3::ACL_PUBLIC_READ : S3::ACL_PRIVATE)); + S3::deleteObject(module::get_var("aws_s3", "bucket_name"), self::get_resource_url("th/" . $old_filename)); + } + else + aws_s3::upload_item($new_item, aws_s3::UPLOAD_THUMB); + } + + static function remove_item($item) { + self::get_s3(); + + $filename = urldecode($item->relative_path()); + $itype = "I"; + if ($item->is_album()) { + $filename .= "/.album.jpg"; + $itype = "A"; + } + + if ($item->s3_fullsize_uploaded && !$item->is_album()) { + aws_s3::log("[" . $itype . ":" . $item->id . "] Deleting fullsize object"); + $success_fs = S3::deleteObject(module::get_var("aws_s3", "bucket_name"), + self::get_resource_url("fs/" . $filename)); + $item->s3_fullsize_uploaded = !$success_fs; + } + else + $success_fs = true; + + if ($item->s3_resize_uploaded && !$item->is_album()) { + aws_s3::log("[" . $itype . ":" . $item->id . "] Deleting resize object"); + $success_rs = S3::deleteObject(module::get_var("aws_s3", "bucket_name"), + self::get_resource_url("rs/" . $filename)); + $item->s3_resize_uploaded = !$success_rs; + } + else + $success_rs = true; + + if ($item->s3_thumb_uploaded) { + aws_s3::log("[" . $itype . ":" . $item->id . "] Deleting thumbnail object"); + $success_th = S3::deleteObject(module::get_var("aws_s3", "bucket_name"), + self::get_resource_url("th/" . $filename)); + $item->s3_thumb_uploaded = !$success_th; + } + else + $success_th = true; + + $item->save_s3_meta(); + + $success = $success_fs && $success_th && $success_rs; + aws_s3::log("S3 delete success: " . $success); + return $success; + } + + static function getAuthenticatedURL($bucket, $uri) { + self::get_s3(); + + return S3::getAuthenticatedURL($bucket, $uri, 60); + } + + static function validate_number($field) { + if (preg_match("/\D/", $field->value)) + $field->add_error("not_numeric", 1); + } + + static function validate_bucket($field) { + if (preg_match("/[^a-zA-Z0-9\-\.]/", $field->value)) + $field->add_error("invalid", 1); + } + + // @TODO: Write validation function (check with S3) + static function validate_access_details($access_key, $secret_key, $bucket_name) { + require_once(MODPATH . "aws_s3/lib/s3.php"); + S3::setAuth($access_key, $secret_key); + S3::$useSSL = false; + + $success_test = S3::putObjectString((string)time(), $bucket_name, ".s3_test"); + if ($success_test) + S3::deleteObject($bucket_name, ".s3_test"); + + return $success_test; + } + + static function base64_filename(Item_Model $item) { + $file_path = explode("/", $item->relative_path()); + return base64_encode(end($file_path)); + } + + static function can_schedule() { + if (!module::is_active("scheduler")) { + return false; + } + + return true; + } + + static function schedule_task($task) { + $schedule = ORM::factory("schedule"); + $schedule->add_task($task); + } + + static function schedule_full_sync2() { + $task_def = + Task_Definition::factory() + ->callback("aws_s3_task::sync") + ->name("Amazon S3 bucket synchronisation") + ->severity(log::SUCCESS); + + $task = task::create($task_def, array()); + self::schedule_task($task); + } + + static function schedule_full_sync($this_task) { + if (!self::can_schedule()) + throw new Exception("Unable to initialize schedule"); + + try { + self::schedule_full_sync2(); + + $this_task->status = "Scheduled re-sync task"; + $this_task->done = true; + $this_task->state = "success"; + $this_task->percent_complete = 100; + } + catch (Exception $err) { + $task->done = true; + $thisSynchronise_task->state = "error"; + $this_task->status = $err->getMessage(); + $this_task->log((string)$err); + } + + $this_task->save(); + + if (!module::get_var("aws_s3", "synced", false)) { + site_status::warning( + "Your site has been scheduled for full Amazon S3 re-synchronisation. This message will clear when this has been completed.", + "aws_s3_not_synced" + ); + } + + return true; + } + + static function schedule_item_sync($item) { + if (!self::can_schedule()) + throw new Exception("Unable to initialize schedule"); + + $item_id = null; + if (is_object($item) && $item instanceof Item_Model) + $item_id = $item->id; + else if (is_numeric($item)) + $item_id = $item; + else + throw new Exception("Un-intelligible item reference passed."); + + $task_def = + Task_Definition::factory() + ->callback("aws_s3_task::upload_item") + ->name("Amazon S3 item upload (ID: " . $item_id . ")") + ->severity(log::SUCCESS); + + $task = task::create($task_def, array("item_id" => $item_id)); + + self::schedule_task($task); + } + + +} \ No newline at end of file diff --git a/3.0/modules/aws_s3/helpers/aws_s3_event.php b/3.0/modules/aws_s3/helpers/aws_s3_event.php new file mode 100644 index 00000000..29a9477a --- /dev/null +++ b/3.0/modules/aws_s3/helpers/aws_s3_event.php @@ -0,0 +1,56 @@ +get("settings_menu") + ->append( + Menu::factory("link") + ->id("aws_s3_link") + ->label(t("Amazon S3")) + ->url(url::site("admin/aws_s3")) + ); + } + + static function item_created($item) { + if ($item->id == 1) + return true; + + aws_s3::log("Item created - " . $item->id); + aws_s3::schedule_item_sync($item); + } + + static function item_deleted($item) { + if ($item->id == 1) + return true; + + aws_s3::log("Item deleted - " . $item->id); + aws_s3::remove_item($item); + + ORM::factory("aws_s3_meta", $item->id)->delete(); + } + + static function item_updated($old_item, $new_item) { + if ($new_item->id == 1) + return true; + + if ($new_item->has_aws_s3_meta()) { + aws_s3::log("Item updated - " . $new_item->id); + + if ($old_item->relative_path() == $new_item->relative_path() && $old_item->s3_item_hash == $new_item->s3_item_hash) { + aws_s3::log("nothing changed?!"); + } + else if ($old_item->relative_path() != $new_item->relative_path()) { + aws_s3::log("Item moved..."); + aws_s3::move_item($old_item, $new_item); + } + else { + aws_s3::log("Item hasn't moved. Image updated?"); + aws_s3::remove_item($old_item); + aws_s3::schedule_item_sync($new_item); + } + } + } + +} \ No newline at end of file diff --git a/3.0/modules/aws_s3/helpers/aws_s3_installer.php b/3.0/modules/aws_s3/helpers/aws_s3_installer.php new file mode 100644 index 00000000..0a297dbb --- /dev/null +++ b/3.0/modules/aws_s3/helpers/aws_s3_installer.php @@ -0,0 +1,126 @@ +query("DROP TABLE {aws_s3_meta}"); + } + + static function upgrade($version) { + log::info("aws_s3", "Commencing module upgrade (" . $version . ")"); + switch ($version) { + case 0: { + log::info("aws_s3", "Installing version 1"); + + @mkdir(VARPATH . "modules/aws_s3"); + @mkdir(VARPATH . "modules/aws_s3/log"); + + // installation's unique identifier - allows multiple g3's pointing to the same s3 bucket. + if (!module::get_var("aws_s3", "g3id")) + module::set_var("aws_s3", "g3id", md5(time())); + + module::set_var("aws_s3", "synced", false); + module::set_var("aws_s3", "enabled", false); + module::set_var("aws_s3", "access_key", ""); + module::set_var("aws_s3", "secret_key", ""); + module::set_var("aws_s3", "bucket_name", ""); + + module::set_version("aws_s3", 1); + } + case 1: { + log::info("aws_s3", "Upgrading to version 2"); + $db = Database::instance(); + $db->query("CREATE TABLE {aws_s3_meta} ( + `item_id` int(9) NOT NULL, + `item_hash` varchar(32) NOT NULL DEFAULT '', + `thumb_uploaded` smallint(1) NOT NULL DEFAULT 0, + `resize_uploaded` smallint(1) NOT NULL DEFAULT 0, + `fullsize_uploaded` smallint(1) NOT NULL DEFAULT 0, + `local_deleted` smallint(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`item_id`) + ) DEFAULT CHARSET=utf8;"); + + module::set_var("aws_s3", "upload_thumbs", true); + module::set_var("aws_s3", "upload_resizes", true); + module::set_var("aws_s3", "upload_fullsizes", true); + module::set_var("aws_s3", "s3_storage_only", false); + + if (module::get_var("aws_s3", "synced")) { + // v1 has already synced this installation to s3. mark all the items with the relevant meta data + $items = ORM::factory("item")->find_all(); + foreach ($items as $item) { + aws_s3::log("Updating S3 meta for item ID: " . $item->id); + $item->s3_thumb_uploaded = true; + if (!$item->is_album()) { + $item->s3_resize_uploaded = true; + $item->s3_fullsize_uploaded = true; + } + $item->s3_local_deleted = false; + $item->s3_item_hash = md5($item->relative_path()); + $item->save_s3_meta(); + } + } + else { + // check various states after upgrade from v1.. + + if (module::get_var("aws_s3", "access_key") != "" && + module::get_var("aws_s3", "secret_key") != "" && + module::get_var("aws_s3", "bucket_name") != "" && + aws_s3::validate_access_details(module::get_var("aws_s3", "access_key"), + module::get_var("aws_s3", "secret_key"), + module::get_var("aws_s3", "bucket_name")) + ) { + // details are correct but hasn't been synced. + if (aws_s3::can_schedule()) { + // i can schedule this task + aws_s3::schedule_full_sync2(); + site_status::warning( + "Your site has been scheduled for full Amazon S3 re-synchronisation. This message will clear when this has been completed.", + "aws_s3_not_synced" + ); + } + else { + // i CAN'T schedule it.. + site_status::warning( + t('Your site has not been synchronised to Amazon S3. Until it has, your server will continue to serve image content to your visitors.
      Click here to start the synchronisation task.', + array("url" => html::mark_clean(url::site("admin/maintenance/start/aws_s3_task::manual_sync?csrf=__CSRF__"))) + ), + "aws_s3_not_synced" + ); + } + } + else { + site_status::warning( + t('Amazon S3 module needs configuration. Click here to go to the configuration page.', + array("url" => html::mark_clean(url::site("admin/aws_s3"))) + ), + "aws_s3_not_configured" + ); + } + } + + module::set_version("aws_s3", 2); + } + } + log::info("aws_s3", "Module upgrade complete"); + } + + static function deactivate() {} + static function activate() {} + static function can_activate() { + $messages = array(); + if (!function_exists("curl_init")) { + $messages['error'][] = "The S3 library (and this module) depend on the php5-curl extension. Please install this extension and try again."; + } + if (!module::is_active("scheduler")) { + $messages['warn'][] = "The 'Scheduler' module is not installed/active. Scheduled maintenance tasks such as synchronisation will not be available."; + } + return $messages; + } + +} \ No newline at end of file diff --git a/3.0/modules/aws_s3/helpers/aws_s3_task.php b/3.0/modules/aws_s3/helpers/aws_s3_task.php new file mode 100644 index 00000000..f0dcb701 --- /dev/null +++ b/3.0/modules/aws_s3/helpers/aws_s3_task.php @@ -0,0 +1,193 @@ +callback("aws_s3::schedule_full_sync") + ->name(t("Synchronise with Amazon S3")) + ->description(t("Schedule a task to synchronise your Gallery 3 data/images with your Amazon S3 bucket")) + ->severity(log::SUCCESS) + ->set_flags(Task_Definition::CAN_RUN_NOW)); + else + return array(Task_Definition::factory() + ->callback("aws_s3_task::manual_sync") + ->name(t("Synchronise with Amazon S3")) + ->description(t("Synchronise your Gallery 3 data/images with your Amazon S3 bucket")) + ->severity(log::SUCCESS)); + + } + + static function upload_item($task) { + aws_s3::log("aws_s3_task::upload_item called"); + + $item = ORM::factory("item", $task->get("item_id")); + + aws_s3::log("Commencing upload task for item " . $item->id); + + $task->status = "Commencing upload"; + $task->percent_complete = 0; + $task->save(); + if (aws_s3::upload_item($item, aws_s3::get_upload_flags())) { + $task->percent_complete = 100; + $task->done = true; + $task->state = "success"; + $task->status = "Upload complete"; + } + else { + $task->done = false; + $task->state = "error"; + $task->status = "Upload failed"; + } + $task->save(); + } + + static function manual_sync($task) { + aws_s3::log("Amazon S3 manual re-sync started."); + + if (!$task->get("mode")) { + $task->set("mode", "init"); + } + + aws_s3::log("mode: " . $task->get("mode")); + switch ($task->get("mode")) { + case "init": { + batch::start(); + $items = ORM::factory("item")->find_all(); + $task->set("total_count", count($items)); + + if (count($items) <= 50) + $task->set("batch", 1); + else if (count($items) > 50 && count($items) <= 500) + $task->set("batch", 5); + else if (count($items) > 500 && count($items) <= 5000) + $task->set("batch", 10); + else if (count($items) > 5000) + $task->set("batch", 25); + + $task->set("completed", 0); + $task->state = "running"; + + if (!module::get_var("aws_s3", "synced", false)) { + $task->set("mode", "clean"); + $task->status = "Emptying contents of bucket"; + } + else { + $task->status = "Uploading items..."; + $task->percent_complete = 10; + $task->set("mode", "upload"); + } + } break; + case "clean": { + aws_s3::log("Emptying contents of bucket"); + + require_once(MODPATH . "aws_s3/lib/s3.php"); + $s3 = new S3(module::get_var("aws_s3", "access_key"), module::get_var("aws_s3", "secret_key")); + + $bucket = module::get_var("aws_s3", "bucket_name"); + $resource = aws_s3::get_resource_url(""); + $stuff = array_reverse(S3::getBucket($bucket, $resource)); + $i = 0; + foreach ($stuff as $uri => $item) { + $i++; + aws_s3::log("Removing " . $uri . " from S3"); + S3::deleteObject($bucket, $uri); + $task->percent_complete = round(20 * ($i / count($stuff))); + $task->save(); + } + $task->set("mode", "upload"); + $task->status = "Uploading items..."; + } break; + case "upload": { + $items = ORM::factory("item")->find_all($task->get("batch"), $task->get("completed")); + foreach ($items as $item) { + aws_s3::upload_item($item, aws_s3::get_upload_flags()); + $task->set("completed", $task->get("completed") + 1); + } + $task->percent_complete = (90 * ($task->get("completed") / $task->get("total_count"))) + 10; + $task->status = "Uploaded " . $task->get("completed") . " of " . $task->get("total_count") . " items..."; + + if ($task->get("completed") == $task->get("total_count")) { + $task->set("mode", "complete"); + } + } break; + case "complete": { + $task->done = true; + $task->state = "success"; + $task->percent_complete = 100; + $task->status = "Completed."; + module::set_var("aws_s3", "synced", true); + site_status::clear("aws_s3_not_synced"); + batch::stop(); + } break; + } + aws_s3::log("End of function.."); + $task->save(); + } + + static function sync($task) { + aws_s3::log("Amazon S3 Re-sync task started.."); + + batch::start(); + $items = ORM::factory("item")->find_all(); + + $task->set("total_count", count($items)); + $task->set("completed", 0); + + if (!module::get_var("aws_s3", "synced", false)) { + aws_s3::log("Emptying contents of bucket"); + $task->status = "Emptying contents of bucket"; + $task->save(); + + require_once(MODPATH . "aws_s3/lib/s3.php"); + $s3 = new S3(module::get_var("aws_s3", "access_key"), module::get_var("aws_s3", "secret_key")); + + $bucket = module::get_var("aws_s3", "bucket_name"); + $resource = aws_s3::get_resource_url(""); + $stuff = array_reverse(S3::getBucket($bucket, $resource)); + $i = 0; + foreach ($stuff as $uri => $item) { + $i++; + aws_s3::log("Removing " . $uri . " from S3"); + S3::deleteObject($bucket, $uri); + $task->percent_complete = round(20 * ($i / count($stuff))); + $task->save(); + } + } + + $task->percent_complete = 20; + aws_s3::log("Commencing upload tasks"); + $task->state = "Commencing upload..."; + $task->save(); + + $completed = $task->get("completed", 0); + + $items = ORM::factory("item")->find_all(); + foreach ($items as $item) { + try { + if ($item->id > 1) + aws_s3::upload_item($item, aws_s3::get_upload_flags()); + } + catch (Exception $err) {} + $completed++; + + $task->set("completed", $completed); + $task->percent_complete = round(80 * ($completed / $task->get("total_count"))) + 20; + $task->status = $completed . " of " . $task->get("total_count"). " uploaded."; + $task->save(); + } + + $task->percent_complete = 100; + $task->state = "success"; + $task->done = true; + aws_s3::log("Sync task completed successfully"); + $task->status = "Sync task completed successfully"; + module::set_var("aws_s3", "synced", true); + site_status::clear("aws_s3_not_synced"); + batch::stop(); + + $task->save(); + } + +} \ No newline at end of file diff --git a/3.0/modules/aws_s3/lib/s3.php b/3.0/modules/aws_s3/lib/s3.php new file mode 100644 index 00000000..b2ce6cec --- /dev/null +++ b/3.0/modules/aws_s3/lib/s3.php @@ -0,0 +1,1367 @@ +getResponse(); + if ($rest->error === false && $rest->code !== 200) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::listBuckets(): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } + $results = array(); + if (!isset($rest->body->Buckets)) return $results; + + if ($detailed) { + if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName)) + $results['owner'] = array( + 'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->ID + ); + $results['buckets'] = array(); + foreach ($rest->body->Buckets->Bucket as $b) + $results['buckets'][] = array( + 'name' => (string)$b->Name, 'time' => strtotime((string)$b->CreationDate) + ); + } else + foreach ($rest->body->Buckets->Bucket as $b) $results[] = (string)$b->Name; + + return $results; + } + + + /* + * Get contents for a bucket + * + * If maxKeys is null this method will loop through truncated result sets + * + * @param string $bucket Bucket name + * @param string $prefix Prefix + * @param string $marker Marker (last file listed) + * @param string $maxKeys Max keys (maximum number of keys to return) + * @param string $delimiter Delimiter + * @param boolean $returnCommonPrefixes Set to true to return CommonPrefixes + * @return array | false + */ + public static function getBucket($bucket, $prefix = null, $marker = null, $maxKeys = null, $delimiter = null, $returnCommonPrefixes = false) { + $rest = new S3Request('GET', $bucket, ''); + if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix); + if ($marker !== null && $marker !== '') $rest->setParameter('marker', $marker); + if ($maxKeys !== null && $maxKeys !== '') $rest->setParameter('max-keys', $maxKeys); + if ($delimiter !== null && $delimiter !== '') $rest->setParameter('delimiter', $delimiter); + $response = $rest->getResponse(); + if ($response->error === false && $response->code !== 200) + $response->error = array('code' => $response->code, 'message' => 'Unexpected HTTP status'); + if ($response->error !== false) { + trigger_error(sprintf("S3::getBucket(): [%s] %s", $response->error['code'], $response->error['message']), E_USER_WARNING); + return false; + } + + $results = array(); + + $nextMarker = null; + if (isset($response->body, $response->body->Contents)) + foreach ($response->body->Contents as $c) { + $results[(string)$c->Key] = array( + 'name' => (string)$c->Key, + 'time' => strtotime((string)$c->LastModified), + 'size' => (int)$c->Size, + 'hash' => substr((string)$c->ETag, 1, -1) + ); + $nextMarker = (string)$c->Key; + } + + if ($returnCommonPrefixes && isset($response->body, $response->body->CommonPrefixes)) + foreach ($response->body->CommonPrefixes as $c) + $results[(string)$c->Prefix] = array('prefix' => (string)$c->Prefix); + + if (isset($response->body, $response->body->IsTruncated) && + (string)$response->body->IsTruncated == 'false') return $results; + + if (isset($response->body, $response->body->NextMarker)) + $nextMarker = (string)$response->body->NextMarker; + + // Loop through truncated results if maxKeys isn't specified + if ($maxKeys == null && $nextMarker !== null && (string)$response->body->IsTruncated == 'true') + do { + $rest = new S3Request('GET', $bucket, ''); + if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix); + $rest->setParameter('marker', $nextMarker); + if ($delimiter !== null && $delimiter !== '') $rest->setParameter('delimiter', $delimiter); + + if (($response = $rest->getResponse(true)) == false || $response->code !== 200) break; + + if (isset($response->body, $response->body->Contents)) + foreach ($response->body->Contents as $c) { + $results[(string)$c->Key] = array( + 'name' => (string)$c->Key, + 'time' => strtotime((string)$c->LastModified), + 'size' => (int)$c->Size, + 'hash' => substr((string)$c->ETag, 1, -1) + ); + $nextMarker = (string)$c->Key; + } + + if ($returnCommonPrefixes && isset($response->body, $response->body->CommonPrefixes)) + foreach ($response->body->CommonPrefixes as $c) + $results[(string)$c->Prefix] = array('prefix' => (string)$c->Prefix); + + if (isset($response->body, $response->body->NextMarker)) + $nextMarker = (string)$response->body->NextMarker; + + } while ($response !== false && (string)$response->body->IsTruncated == 'true'); + + return $results; + } + + + /** + * Put a bucket + * + * @param string $bucket Bucket name + * @param constant $acl ACL flag + * @param string $location Set as "EU" to create buckets hosted in Europe + * @return boolean + */ + public static function putBucket($bucket, $acl = self::ACL_PRIVATE, $location = false) { + $rest = new S3Request('PUT', $bucket, ''); + $rest->setAmzHeader('x-amz-acl', $acl); + + if ($location !== false) { + $dom = new DOMDocument; + $createBucketConfiguration = $dom->createElement('CreateBucketConfiguration'); + $locationConstraint = $dom->createElement('LocationConstraint', strtoupper($location)); + $createBucketConfiguration->appendChild($locationConstraint); + $dom->appendChild($createBucketConfiguration); + $rest->data = $dom->saveXML(); + $rest->size = strlen($rest->data); + $rest->setHeader('Content-Type', 'application/xml'); + } + $rest = $rest->getResponse(); + + if ($rest->error === false && $rest->code !== 200) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::putBucket({$bucket}, {$acl}, {$location}): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } + return true; + } + + + /** + * Delete an empty bucket + * + * @param string $bucket Bucket name + * @return boolean + */ + public static function deleteBucket($bucket) { + $rest = new S3Request('DELETE', $bucket); + $rest = $rest->getResponse(); + if ($rest->error === false && $rest->code !== 204) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::deleteBucket({$bucket}): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } + return true; + } + + + /** + * Create input info array for putObject() + * + * @param string $file Input file + * @param mixed $md5sum Use MD5 hash (supply a string if you want to use your own) + * @return array | false + */ + public static function inputFile($file, $md5sum = true) { + if (!file_exists($file) || !is_file($file) || !is_readable($file)) { + trigger_error('S3::inputFile(): Unable to open input file: '.$file, E_USER_WARNING); + return false; + } + return array('file' => $file, 'size' => filesize($file), + 'md5sum' => $md5sum !== false ? (is_string($md5sum) ? $md5sum : + base64_encode(md5_file($file, true))) : ''); + } + + + /** + * Create input array info for putObject() with a resource + * + * @param string $resource Input resource to read from + * @param integer $bufferSize Input byte size + * @param string $md5sum MD5 hash to send (optional) + * @return array | false + */ + public static function inputResource(&$resource, $bufferSize, $md5sum = '') { + if (!is_resource($resource) || $bufferSize < 0) { + trigger_error('S3::inputResource(): Invalid resource or buffer size', E_USER_WARNING); + return false; + } + $input = array('size' => $bufferSize, 'md5sum' => $md5sum); + $input['fp'] =& $resource; + return $input; + } + + + /** + * Put an object + * + * @param mixed $input Input data + * @param string $bucket Bucket name + * @param string $uri Object URI + * @param constant $acl ACL constant + * @param array $metaHeaders Array of x-amz-meta-* headers + * @param array $requestHeaders Array of request headers or content type as a string + * @return boolean + */ + public static function putObject($input, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $requestHeaders = array()) { + if ($input === false) return false; + $rest = new S3Request('PUT', $bucket, $uri); + + if (is_string($input) || is_numeric($input)) $input = array( + 'data' => $input, 'size' => strlen($input), + 'md5sum' => base64_encode(md5($input, true)) + ); + + // Data + if (isset($input['fp'])) + $rest->fp =& $input['fp']; + elseif (isset($input['file'])) + $rest->fp = @fopen($input['file'], 'rb'); + elseif (isset($input['data'])) + $rest->data = $input['data']; + + // Content-Length (required) + if (isset($input['size']) && $input['size'] >= 0) + $rest->size = $input['size']; + else { + if (isset($input['file'])) + $rest->size = filesize($input['file']); + elseif (isset($input['data'])) + $rest->size = strlen($input['data']); + } + + // Custom request headers (Content-Type, Content-Disposition, Content-Encoding) + if (is_array($requestHeaders)) + foreach ($requestHeaders as $h => $v) $rest->setHeader($h, $v); + elseif (is_string($requestHeaders)) // Support for legacy contentType parameter + $input['type'] = $requestHeaders; + + // Content-Type + if (!isset($input['type'])) { + if (isset($requestHeaders['Content-Type'])) + $input['type'] =& $requestHeaders['Content-Type']; + elseif (isset($input['file'])) + $input['type'] = self::__getMimeType($input['file']); + else + $input['type'] = 'application/octet-stream'; + } + + // We need to post with Content-Length and Content-Type, MD5 is optional + if ($rest->size >= 0 && ($rest->fp !== false || $rest->data !== false)) { + $rest->setHeader('Content-Type', $input['type']); + if (isset($input['md5sum'])) $rest->setHeader('Content-MD5', $input['md5sum']); + + $rest->setAmzHeader('x-amz-acl', $acl); + foreach ($metaHeaders as $h => $v) $rest->setAmzHeader('x-amz-meta-'.$h, $v); + $rest->getResponse(); + } else + $rest->response->error = array('code' => 0, 'message' => 'Missing input parameters'); + + if ($rest->response->error === false && $rest->response->code !== 200) + $rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status'); + if ($rest->response->error !== false) { + trigger_error(sprintf("S3::putObject(): [%s] %s", $rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING); + return false; + } + return true; + } + + + /** + * Put an object from a file (legacy function) + * + * @param string $file Input file path + * @param string $bucket Bucket name + * @param string $uri Object URI + * @param constant $acl ACL constant + * @param array $metaHeaders Array of x-amz-meta-* headers + * @param string $contentType Content type + * @return boolean + */ + public static function putObjectFile($file, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = null) { + return self::putObject(self::inputFile($file), $bucket, $uri, $acl, $metaHeaders, $contentType); + } + + + /** + * Put an object from a string (legacy function) + * + * @param string $string Input data + * @param string $bucket Bucket name + * @param string $uri Object URI + * @param constant $acl ACL constant + * @param array $metaHeaders Array of x-amz-meta-* headers + * @param string $contentType Content type + * @return boolean + */ + public static function putObjectString($string, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = 'text/plain') { + return self::putObject($string, $bucket, $uri, $acl, $metaHeaders, $contentType); + } + + + /** + * Get an object + * + * @param string $bucket Bucket name + * @param string $uri Object URI + * @param mixed $saveTo Filename or resource to write to + * @return mixed + */ + public static function getObject($bucket, $uri, $saveTo = false) { + $rest = new S3Request('GET', $bucket, $uri); + if ($saveTo !== false) { + if (is_resource($saveTo)) + $rest->fp =& $saveTo; + else + if (($rest->fp = @fopen($saveTo, 'wb')) !== false) + $rest->file = realpath($saveTo); + else + $rest->response->error = array('code' => 0, 'message' => 'Unable to open save file for writing: '.$saveTo); + } + if ($rest->response->error === false) $rest->getResponse(); + + if ($rest->response->error === false && $rest->response->code !== 200) + $rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status'); + if ($rest->response->error !== false) { + trigger_error(sprintf("S3::getObject({$bucket}, {$uri}): [%s] %s", + $rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING); + return false; + } + return $rest->response; + } + + + /** + * Get object information + * + * @param string $bucket Bucket name + * @param string $uri Object URI + * @param boolean $returnInfo Return response information + * @return mixed | false + */ + public static function getObjectInfo($bucket, $uri, $returnInfo = true) { + $rest = new S3Request('HEAD', $bucket, $uri); + $rest = $rest->getResponse(); + if ($rest->error === false && ($rest->code !== 200 && $rest->code !== 404)) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::getObjectInfo({$bucket}, {$uri}): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } + return $rest->code == 200 ? $returnInfo ? $rest->headers : true : false; + } + + + /** + * Copy an object + * + * @param string $bucket Source bucket name + * @param string $uri Source object URI + * @param string $bucket Destination bucket name + * @param string $uri Destination object URI + * @param constant $acl ACL constant + * @param array $metaHeaders Optional array of x-amz-meta-* headers + * @param array $requestHeaders Optional array of request headers (content type, disposition, etc.) + * @return mixed | false + */ + public static function copyObject($srcBucket, $srcUri, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $requestHeaders = array()) { + $rest = new S3Request('PUT', $bucket, $uri); + $rest->setHeader('Content-Length', 0); + foreach ($requestHeaders as $h => $v) $rest->setHeader($h, $v); + foreach ($metaHeaders as $h => $v) $rest->setAmzHeader('x-amz-meta-'.$h, $v); + $rest->setAmzHeader('x-amz-acl', $acl); + $rest->setAmzHeader('x-amz-copy-source', sprintf('/%s/%s', $srcBucket, $srcUri)); + if (sizeof($requestHeaders) > 0 || sizeof($metaHeaders) > 0) + $rest->setAmzHeader('x-amz-metadata-directive', 'REPLACE'); + $rest = $rest->getResponse(); + if ($rest->error === false && $rest->code !== 200) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::copyObject({$srcBucket}, {$srcUri}, {$bucket}, {$uri}): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } + return isset($rest->body->LastModified, $rest->body->ETag) ? array( + 'time' => strtotime((string)$rest->body->LastModified), + 'hash' => substr((string)$rest->body->ETag, 1, -1) + ) : false; + } + + + /** + * Set logging for a bucket + * + * @param string $bucket Bucket name + * @param string $targetBucket Target bucket (where logs are stored) + * @param string $targetPrefix Log prefix (e,g; domain.com-) + * @return boolean + */ + public static function setBucketLogging($bucket, $targetBucket, $targetPrefix = null) { + // The S3 log delivery group has to be added to the target bucket's ACP + if ($targetBucket !== null && ($acp = self::getAccessControlPolicy($targetBucket, '')) !== false) { + // Only add permissions to the target bucket when they do not exist + $aclWriteSet = false; + $aclReadSet = false; + foreach ($acp['acl'] as $acl) + if ($acl['type'] == 'Group' && $acl['uri'] == 'http://acs.amazonaws.com/groups/s3/LogDelivery') { + if ($acl['permission'] == 'WRITE') $aclWriteSet = true; + elseif ($acl['permission'] == 'READ_ACP') $aclReadSet = true; + } + if (!$aclWriteSet) $acp['acl'][] = array( + 'type' => 'Group', 'uri' => 'http://acs.amazonaws.com/groups/s3/LogDelivery', 'permission' => 'WRITE' + ); + if (!$aclReadSet) $acp['acl'][] = array( + 'type' => 'Group', 'uri' => 'http://acs.amazonaws.com/groups/s3/LogDelivery', 'permission' => 'READ_ACP' + ); + if (!$aclReadSet || !$aclWriteSet) self::setAccessControlPolicy($targetBucket, '', $acp); + } + + $dom = new DOMDocument; + $bucketLoggingStatus = $dom->createElement('BucketLoggingStatus'); + $bucketLoggingStatus->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/'); + if ($targetBucket !== null) { + if ($targetPrefix == null) $targetPrefix = $bucket . '-'; + $loggingEnabled = $dom->createElement('LoggingEnabled'); + $loggingEnabled->appendChild($dom->createElement('TargetBucket', $targetBucket)); + $loggingEnabled->appendChild($dom->createElement('TargetPrefix', $targetPrefix)); + // TODO: Add TargetGrants? + $bucketLoggingStatus->appendChild($loggingEnabled); + } + $dom->appendChild($bucketLoggingStatus); + + $rest = new S3Request('PUT', $bucket, ''); + $rest->setParameter('logging', null); + $rest->data = $dom->saveXML(); + $rest->size = strlen($rest->data); + $rest->setHeader('Content-Type', 'application/xml'); + $rest = $rest->getResponse(); + if ($rest->error === false && $rest->code !== 200) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::setBucketLogging({$bucket}, {$uri}): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } + return true; + } + + + /** + * Get logging status for a bucket + * + * This will return false if logging is not enabled. + * Note: To enable logging, you also need to grant write access to the log group + * + * @param string $bucket Bucket name + * @return array | false + */ + public static function getBucketLogging($bucket) { + $rest = new S3Request('GET', $bucket, ''); + $rest->setParameter('logging', null); + $rest = $rest->getResponse(); + if ($rest->error === false && $rest->code !== 200) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::getBucketLogging({$bucket}): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } + if (!isset($rest->body->LoggingEnabled)) return false; // No logging + return array( + 'targetBucket' => (string)$rest->body->LoggingEnabled->TargetBucket, + 'targetPrefix' => (string)$rest->body->LoggingEnabled->TargetPrefix, + ); + } + + + /** + * Disable bucket logging + * + * @param string $bucket Bucket name + * @return boolean + */ + public static function disableBucketLogging($bucket) { + return self::setBucketLogging($bucket, null); + } + + + /** + * Get a bucket's location + * + * @param string $bucket Bucket name + * @return string | false + */ + public static function getBucketLocation($bucket) { + $rest = new S3Request('GET', $bucket, ''); + $rest->setParameter('location', null); + $rest = $rest->getResponse(); + if ($rest->error === false && $rest->code !== 200) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::getBucketLocation({$bucket}): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } + return (isset($rest->body[0]) && (string)$rest->body[0] !== '') ? (string)$rest->body[0] : 'US'; + } + + + /** + * Set object or bucket Access Control Policy + * + * @param string $bucket Bucket name + * @param string $uri Object URI + * @param array $acp Access Control Policy Data (same as the data returned from getAccessControlPolicy) + * @return boolean + */ + public static function setAccessControlPolicy($bucket, $uri = '', $acp = array()) { + $dom = new DOMDocument; + $dom->formatOutput = true; + $accessControlPolicy = $dom->createElement('AccessControlPolicy'); + $accessControlList = $dom->createElement('AccessControlList'); + + // It seems the owner has to be passed along too + $owner = $dom->createElement('Owner'); + $owner->appendChild($dom->createElement('ID', $acp['owner']['id'])); + $owner->appendChild($dom->createElement('DisplayName', $acp['owner']['name'])); + $accessControlPolicy->appendChild($owner); + + foreach ($acp['acl'] as $g) { + $grant = $dom->createElement('Grant'); + $grantee = $dom->createElement('Grantee'); + $grantee->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + if (isset($g['id'])) { // CanonicalUser (DisplayName is omitted) + $grantee->setAttribute('xsi:type', 'CanonicalUser'); + $grantee->appendChild($dom->createElement('ID', $g['id'])); + } elseif (isset($g['email'])) { // AmazonCustomerByEmail + $grantee->setAttribute('xsi:type', 'AmazonCustomerByEmail'); + $grantee->appendChild($dom->createElement('EmailAddress', $g['email'])); + } elseif ($g['type'] == 'Group') { // Group + $grantee->setAttribute('xsi:type', 'Group'); + $grantee->appendChild($dom->createElement('URI', $g['uri'])); + } + $grant->appendChild($grantee); + $grant->appendChild($dom->createElement('Permission', $g['permission'])); + $accessControlList->appendChild($grant); + } + + $accessControlPolicy->appendChild($accessControlList); + $dom->appendChild($accessControlPolicy); + + $rest = new S3Request('PUT', $bucket, $uri); + $rest->setParameter('acl', null); + $rest->data = $dom->saveXML(); + $rest->size = strlen($rest->data); + $rest->setHeader('Content-Type', 'application/xml'); + $rest = $rest->getResponse(); + if ($rest->error === false && $rest->code !== 200) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::setAccessControlPolicy({$bucket}, {$uri}): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } + return true; + } + + + /** + * Get object or bucket Access Control Policy + * + * @param string $bucket Bucket name + * @param string $uri Object URI + * @return mixed | false + */ + public static function getAccessControlPolicy($bucket, $uri = '') { + $rest = new S3Request('GET', $bucket, $uri); + $rest->setParameter('acl', null); + $rest = $rest->getResponse(); + if ($rest->error === false && $rest->code !== 200) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::getAccessControlPolicy({$bucket}, {$uri}): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } + + $acp = array(); + if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName)) { + $acp['owner'] = array( + 'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->DisplayName + ); + } + if (isset($rest->body->AccessControlList)) { + $acp['acl'] = array(); + foreach ($rest->body->AccessControlList->Grant as $grant) { + foreach ($grant->Grantee as $grantee) { + if (isset($grantee->ID, $grantee->DisplayName)) // CanonicalUser + $acp['acl'][] = array( + 'type' => 'CanonicalUser', + 'id' => (string)$grantee->ID, + 'name' => (string)$grantee->DisplayName, + 'permission' => (string)$grant->Permission + ); + elseif (isset($grantee->EmailAddress)) // AmazonCustomerByEmail + $acp['acl'][] = array( + 'type' => 'AmazonCustomerByEmail', + 'email' => (string)$grantee->EmailAddress, + 'permission' => (string)$grant->Permission + ); + elseif (isset($grantee->URI)) // Group + $acp['acl'][] = array( + 'type' => 'Group', + 'uri' => (string)$grantee->URI, + 'permission' => (string)$grant->Permission + ); + else continue; + } + } + } + return $acp; + } + + + /** + * Delete an object + * + * @param string $bucket Bucket name + * @param string $uri Object URI + * @return boolean + */ + public static function deleteObject($bucket, $uri) { + $rest = new S3Request('DELETE', $bucket, $uri); + $rest = $rest->getResponse(); + if ($rest->error === false && $rest->code !== 204) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::deleteObject(): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } + return true; + } + + + /** + * Get a query string authenticated URL + * + * @param string $bucket Bucket name + * @param string $uri Object URI + * @param integer $lifetime Lifetime in seconds + * @param boolean $hostBucket Use the bucket name as the hostname + * @param boolean $https Use HTTPS ($hostBucket should be false for SSL verification) + * @return string + */ + public static function getAuthenticatedURL($bucket, $uri, $lifetime, $hostBucket = false, $https = false) { + $expires = time() + $lifetime; + $uri = str_replace('%2F', '/', rawurlencode($uri)); // URI should be encoded (thanks Sean O'Dea) + return sprintf(($https ? 'https' : 'http').'://%s/%s?AWSAccessKeyId=%s&Expires=%u&Signature=%s', + $hostBucket ? $bucket : $bucket.'.s3.amazonaws.com', $uri, self::$__accessKey, $expires, + urlencode(self::__getHash("GET\n\n\n{$expires}\n/{$bucket}/{$uri}"))); + } + + /** + * Get upload POST parameters for form uploads + * + * @param string $bucket Bucket name + * @param string $uriPrefix Object URI prefix + * @param constant $acl ACL constant + * @param integer $lifetime Lifetime in seconds + * @param integer $maxFileSize Maximum filesize in bytes (default 5MB) + * @param string $successRedirect Redirect URL or 200 / 201 status code + * @param array $amzHeaders Array of x-amz-meta-* headers + * @param array $headers Array of request headers or content type as a string + * @param boolean $flashVars Includes additional "Filename" variable posted by Flash + * @return object + */ + public static function getHttpUploadPostParams($bucket, $uriPrefix = '', $acl = self::ACL_PRIVATE, $lifetime = 3600, $maxFileSize = 5242880, $successRedirect = "201", $amzHeaders = array(), $headers = array(), $flashVars = false) { + // Create policy object + $policy = new stdClass; + $policy->expiration = gmdate('Y-m-d\TH:i:s\Z', (time() + $lifetime)); + $policy->conditions = array(); + $obj = new stdClass; $obj->bucket = $bucket; array_push($policy->conditions, $obj); + $obj = new stdClass; $obj->acl = $acl; array_push($policy->conditions, $obj); + + $obj = new stdClass; // 200 for non-redirect uploads + if (is_numeric($successRedirect) && in_array((int)$successRedirect, array(200, 201))) + $obj->success_action_status = (string)$successRedirect; + else // URL + $obj->success_action_redirect = $successRedirect; + array_push($policy->conditions, $obj); + + array_push($policy->conditions, array('starts-with', '$key', $uriPrefix)); + if ($flashVars) array_push($policy->conditions, array('starts-with', '$Filename', '')); + foreach (array_keys($headers) as $headerKey) + array_push($policy->conditions, array('starts-with', '$'.$headerKey, '')); + foreach ($amzHeaders as $headerKey => $headerVal) { + $obj = new stdClass; $obj->{$headerKey} = (string)$headerVal; array_push($policy->conditions, $obj); + } + array_push($policy->conditions, array('content-length-range', 0, $maxFileSize)); + $policy = base64_encode(str_replace('\/', '/', json_encode($policy))); + + // Create parameters + $params = new stdClass; + $params->AWSAccessKeyId = self::$__accessKey; + $params->key = $uriPrefix.'${filename}'; + $params->acl = $acl; + $params->policy = $policy; unset($policy); + $params->signature = self::__getHash($params->policy); + if (is_numeric($successRedirect) && in_array((int)$successRedirect, array(200, 201))) + $params->success_action_status = (string)$successRedirect; + else + $params->success_action_redirect = $successRedirect; + foreach ($headers as $headerKey => $headerVal) $params->{$headerKey} = (string)$headerVal; + foreach ($amzHeaders as $headerKey => $headerVal) $params->{$headerKey} = (string)$headerVal; + return $params; + } + + /** + * Create a CloudFront distribution + * + * @param string $bucket Bucket name + * @param boolean $enabled Enabled (true/false) + * @param array $cnames Array containing CNAME aliases + * @param string $comment Use the bucket name as the hostname + * @return array | false + */ + public static function createDistribution($bucket, $enabled = true, $cnames = array(), $comment = '') { + self::$useSSL = true; // CloudFront requires SSL + $rest = new S3Request('POST', '', '2008-06-30/distribution', 'cloudfront.amazonaws.com'); + $rest->data = self::__getCloudFrontDistributionConfigXML($bucket.'.s3.amazonaws.com', $enabled, $comment, (string)microtime(true), $cnames); + $rest->size = strlen($rest->data); + $rest->setHeader('Content-Type', 'application/xml'); + $rest = self::__getCloudFrontResponse($rest); + + if ($rest->error === false && $rest->code !== 201) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::createDistribution({$bucket}, ".(int)$enabled.", '$comment'): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } elseif ($rest->body instanceof SimpleXMLElement) + return self::__parseCloudFrontDistributionConfig($rest->body); + return false; + } + + + /** + * Get CloudFront distribution info + * + * @param string $distributionId Distribution ID from listDistributions() + * @return array | false + */ + public static function getDistribution($distributionId) { + self::$useSSL = true; // CloudFront requires SSL + $rest = new S3Request('GET', '', '2008-06-30/distribution/'.$distributionId, 'cloudfront.amazonaws.com'); + $rest = self::__getCloudFrontResponse($rest); + + if ($rest->error === false && $rest->code !== 200) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::getDistribution($distributionId): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } elseif ($rest->body instanceof SimpleXMLElement) { + $dist = self::__parseCloudFrontDistributionConfig($rest->body); + $dist['hash'] = $rest->headers['hash']; + return $dist; + } + return false; + } + + + /** + * Update a CloudFront distribution + * + * @param array $dist Distribution array info identical to output of getDistribution() + * @return array | false + */ + public static function updateDistribution($dist) { + self::$useSSL = true; // CloudFront requires SSL + $rest = new S3Request('PUT', '', '2008-06-30/distribution/'.$dist['id'].'/config', 'cloudfront.amazonaws.com'); + $rest->data = self::__getCloudFrontDistributionConfigXML($dist['origin'], $dist['enabled'], $dist['comment'], $dist['callerReference'], $dist['cnames']); + $rest->size = strlen($rest->data); + $rest->setHeader('If-Match', $dist['hash']); + $rest = self::__getCloudFrontResponse($rest); + + if ($rest->error === false && $rest->code !== 200) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::updateDistribution({$dist['id']}, ".(int)$enabled.", '$comment'): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } else { + $dist = self::__parseCloudFrontDistributionConfig($rest->body); + $dist['hash'] = $rest->headers['hash']; + return $dist; + } + return false; + } + + + /** + * Delete a CloudFront distribution + * + * @param array $dist Distribution array info identical to output of getDistribution() + * @return boolean + */ + public static function deleteDistribution($dist) { + self::$useSSL = true; // CloudFront requires SSL + $rest = new S3Request('DELETE', '', '2008-06-30/distribution/'.$dist['id'], 'cloudfront.amazonaws.com'); + $rest->setHeader('If-Match', $dist['hash']); + $rest = self::__getCloudFrontResponse($rest); + + if ($rest->error === false && $rest->code !== 204) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::deleteDistribution({$dist['id']}): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } + return true; + } + + + /** + * Get a list of CloudFront distributions + * + * @return array + */ + public static function listDistributions() { + self::$useSSL = true; // CloudFront requires SSL + $rest = new S3Request('GET', '', '2008-06-30/distribution', 'cloudfront.amazonaws.com'); + $rest = self::__getCloudFrontResponse($rest); + + if ($rest->error === false && $rest->code !== 200) + $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); + if ($rest->error !== false) { + trigger_error(sprintf("S3::listDistributions(): [%s] %s", + $rest->error['code'], $rest->error['message']), E_USER_WARNING); + return false; + } elseif ($rest->body instanceof SimpleXMLElement && isset($rest->body->DistributionSummary)) { + $list = array(); + if (isset($rest->body->Marker, $rest->body->MaxItems, $rest->body->IsTruncated)) { + //$info['marker'] = (string)$rest->body->Marker; + //$info['maxItems'] = (int)$rest->body->MaxItems; + //$info['isTruncated'] = (string)$rest->body->IsTruncated == 'true' ? true : false; + } + foreach ($rest->body->DistributionSummary as $summary) { + $list[(string)$summary->Id] = self::__parseCloudFrontDistributionConfig($summary); + } + return $list; + } + return array(); + } + + + /** + * Get a DistributionConfig DOMDocument + * + * @internal Used to create XML in createDistribution() and updateDistribution() + * @param string $bucket Origin bucket + * @param boolean $enabled Enabled (true/false) + * @param string $comment Comment to append + * @param string $callerReference Caller reference + * @param array $cnames Array of CNAME aliases + * @return string + */ + private static function __getCloudFrontDistributionConfigXML($bucket, $enabled, $comment, $callerReference = '0', $cnames = array()) { + $dom = new DOMDocument('1.0', 'UTF-8'); + $dom->formatOutput = true; + $distributionConfig = $dom->createElement('DistributionConfig'); + $distributionConfig->setAttribute('xmlns', 'http://cloudfront.amazonaws.com/doc/2008-06-30/'); + $distributionConfig->appendChild($dom->createElement('Origin', $bucket)); + $distributionConfig->appendChild($dom->createElement('CallerReference', $callerReference)); + foreach ($cnames as $cname) + $distributionConfig->appendChild($dom->createElement('CNAME', $cname)); + if ($comment !== '') $distributionConfig->appendChild($dom->createElement('Comment', $comment)); + $distributionConfig->appendChild($dom->createElement('Enabled', $enabled ? 'true' : 'false')); + $dom->appendChild($distributionConfig); + return $dom->saveXML(); + } + + + /** + * Parse a CloudFront distribution config + * + * @internal Used to parse the CloudFront DistributionConfig node to an array + * @param object &$node DOMNode + * @return array + */ + private static function __parseCloudFrontDistributionConfig(&$node) { + $dist = array(); + if (isset($node->Id, $node->Status, $node->LastModifiedTime, $node->DomainName)) { + $dist['id'] = (string)$node->Id; + $dist['status'] = (string)$node->Status; + $dist['time'] = strtotime((string)$node->LastModifiedTime); + $dist['domain'] = (string)$node->DomainName; + } + if (isset($node->CallerReference)) + $dist['callerReference'] = (string)$node->CallerReference; + if (isset($node->Comment)) + $dist['comment'] = (string)$node->Comment; + if (isset($node->Enabled, $node->Origin)) { + $dist['origin'] = (string)$node->Origin; + $dist['enabled'] = (string)$node->Enabled == 'true' ? true : false; + } elseif (isset($node->DistributionConfig)) { + $dist = array_merge($dist, self::__parseCloudFrontDistributionConfig($node->DistributionConfig)); + } + if (isset($node->CNAME)) { + $dist['cnames'] = array(); + foreach ($node->CNAME as $cname) $dist['cnames'][(string)$cname] = (string)$cname; + } + return $dist; + } + + + /** + * Grab CloudFront response + * + * @internal Used to parse the CloudFront S3Request::getResponse() output + * @param object &$rest S3Request instance + * @return object + */ + private static function __getCloudFrontResponse(&$rest) { + $rest->getResponse(); + if ($rest->response->error === false && isset($rest->response->body) && + is_string($rest->response->body) && substr($rest->response->body, 0, 5) == 'response->body = simplexml_load_string($rest->response->body); + // Grab CloudFront errors + if (isset($rest->response->body->Error, $rest->response->body->Error->Code, + $rest->response->body->Error->Message)) { + $rest->response->error = array( + 'code' => (string)$rest->response->body->Error->Code, + 'message' => (string)$rest->response->body->Error->Message + ); + unset($rest->response->body); + } + } + return $rest->response; + } + + + /** + * Get MIME type for file + * + * @internal Used to get mime types + * @param string &$file File path + * @return string + */ + public static function __getMimeType(&$file) { + $type = false; + // Fileinfo documentation says fileinfo_open() will use the + // MAGIC env var for the magic file + if (extension_loaded('fileinfo') && isset($_ENV['MAGIC']) && + ($finfo = finfo_open(FILEINFO_MIME, $_ENV['MAGIC'])) !== false) { + if (($type = finfo_file($finfo, $file)) !== false) { + // Remove the charset and grab the last content-type + $type = explode(' ', str_replace('; charset=', ';charset=', $type)); + $type = array_pop($type); + $type = explode(';', $type); + $type = trim(array_shift($type)); + } + finfo_close($finfo); + + // If anyone is still using mime_content_type() + } elseif (function_exists('mime_content_type')) + $type = trim(mime_content_type($file)); + + if ($type !== false && strlen($type) > 0) return $type; + + // Otherwise do it the old fashioned way + static $exts = array( + 'jpg' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png', + 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'ico' => 'image/x-icon', + 'swf' => 'application/x-shockwave-flash', 'pdf' => 'application/pdf', + 'zip' => 'application/zip', 'gz' => 'application/x-gzip', + 'tar' => 'application/x-tar', 'bz' => 'application/x-bzip', + 'bz2' => 'application/x-bzip2', 'txt' => 'text/plain', + 'asc' => 'text/plain', 'htm' => 'text/html', 'html' => 'text/html', + 'css' => 'text/css', 'js' => 'text/javascript', + 'xml' => 'text/xml', 'xsl' => 'application/xsl+xml', + 'ogg' => 'application/ogg', 'mp3' => 'audio/mpeg', 'wav' => 'audio/x-wav', + 'avi' => 'video/x-msvideo', 'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg', + 'mov' => 'video/quicktime', 'flv' => 'video/x-flv', 'php' => 'text/x-php' + ); + $ext = strtolower(pathInfo($file, PATHINFO_EXTENSION)); + return isset($exts[$ext]) ? $exts[$ext] : 'application/octet-stream'; + } + + + /** + * Generate the auth string: "AWS AccessKey:Signature" + * + * @internal Used by S3Request::getResponse() + * @param string $string String to sign + * @return string + */ + public static function __getSignature($string) { + return 'AWS '.self::$__accessKey.':'.self::__getHash($string); + } + + + /** + * Creates a HMAC-SHA1 hash + * + * This uses the hash extension if loaded + * + * @internal Used by __getSignature() + * @param string $string String to sign + * @return string + */ + private static function __getHash($string) { + return base64_encode(extension_loaded('hash') ? + hash_hmac('sha1', $string, self::$__secretKey, true) : pack('H*', sha1( + (str_pad(self::$__secretKey, 64, chr(0x00)) ^ (str_repeat(chr(0x5c), 64))) . + pack('H*', sha1((str_pad(self::$__secretKey, 64, chr(0x00)) ^ + (str_repeat(chr(0x36), 64))) . $string))))); + } + +} + +final class S3Request { + private $verb, $bucket, $uri, $resource = '', $parameters = array(), + $amzHeaders = array(), $headers = array( + 'Host' => '', 'Date' => '', 'Content-MD5' => '', 'Content-Type' => '' + ); + public $fp = false, $size = 0, $data = false, $response; + + + /** + * Constructor + * + * @param string $verb Verb + * @param string $bucket Bucket name + * @param string $uri Object URI + * @return mixed + */ + function __construct($verb, $bucket = '', $uri = '', $defaultHost = 's3.amazonaws.com') { + $this->verb = $verb; + $this->bucket = strtolower($bucket); + $this->uri = $uri !== '' ? '/'.str_replace('%2F', '/', rawurlencode($uri)) : '/'; + + if ($this->bucket !== '') { + $this->headers['Host'] = $this->bucket.'.'.$defaultHost; + $this->resource = '/'.$this->bucket.$this->uri; + } else { + $this->headers['Host'] = $defaultHost; + //$this->resource = strlen($this->uri) > 1 ? '/'.$this->bucket.$this->uri : $this->uri; + $this->resource = $this->uri; + } + $this->headers['Date'] = gmdate('D, d M Y H:i:s T'); + + $this->response = new STDClass; + $this->response->error = false; + } + + + /** + * Set request parameter + * + * @param string $key Key + * @param string $value Value + * @return void + */ + public function setParameter($key, $value) { + $this->parameters[$key] = $value; + } + + + /** + * Set request header + * + * @param string $key Key + * @param string $value Value + * @return void + */ + public function setHeader($key, $value) { + $this->headers[$key] = $value; + } + + + /** + * Set x-amz-meta-* header + * + * @param string $key Key + * @param string $value Value + * @return void + */ + public function setAmzHeader($key, $value) { + $this->amzHeaders[$key] = $value; + } + + + /** + * Get the S3 response + * + * @return object | false + */ + public function getResponse() { + $query = ''; + if (sizeof($this->parameters) > 0) { + $query = substr($this->uri, -1) !== '?' ? '?' : '&'; + foreach ($this->parameters as $var => $value) + if ($value == null || $value == '') $query .= $var.'&'; + // Parameters should be encoded (thanks Sean O'Dea) + else $query .= $var.'='.rawurlencode($value).'&'; + $query = substr($query, 0, -1); + $this->uri .= $query; + + if (array_key_exists('acl', $this->parameters) || + array_key_exists('location', $this->parameters) || + array_key_exists('torrent', $this->parameters) || + array_key_exists('logging', $this->parameters)) + $this->resource .= $query; + } + $url = ((S3::$useSSL && extension_loaded('openssl')) ? + 'https://':'http://').$this->headers['Host'].$this->uri; + //var_dump($this->bucket, $this->uri, $this->resource, $url); + + // Basic setup + $curl = curl_init(); + curl_setopt($curl, CURLOPT_USERAGENT, 'S3/php'); + + if (S3::$useSSL) { + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER , false ); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST , false ); +// curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1); +// curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1); + } + + curl_setopt($curl, CURLOPT_URL, $url); + + // Headers + $headers = array(); $amz = array(); + foreach ($this->amzHeaders as $header => $value) + if (strlen($value) > 0) $headers[] = $header.': '.$value; + foreach ($this->headers as $header => $value) + if (strlen($value) > 0) $headers[] = $header.': '.$value; + + // Collect AMZ headers for signature + foreach ($this->amzHeaders as $header => $value) + if (strlen($value) > 0) $amz[] = strtolower($header).':'.$value; + + // AMZ headers must be sorted + if (sizeof($amz) > 0) { + sort($amz); + $amz = "\n".implode("\n", $amz); + } else $amz = ''; + + // Authorization string (CloudFront stringToSign should only contain a date) + $headers[] = 'Authorization: ' . S3::__getSignature( + $this->headers['Host'] == 'cloudfront.amazonaws.com' ? $this->headers['Date'] : + $this->verb."\n".$this->headers['Content-MD5']."\n". + $this->headers['Content-Type']."\n".$this->headers['Date'].$amz."\n".$this->resource + ); + + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, false); + curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback')); + curl_setopt($curl, CURLOPT_HEADERFUNCTION, array(&$this, '__responseHeaderCallback')); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + + // Request types + switch ($this->verb) { + case 'GET': break; + case 'PUT': case 'POST': // POST only used for CloudFront + if ($this->fp !== false) { + curl_setopt($curl, CURLOPT_PUT, true); + curl_setopt($curl, CURLOPT_INFILE, $this->fp); + if ($this->size >= 0) + curl_setopt($curl, CURLOPT_INFILESIZE, $this->size); + } elseif ($this->data !== false) { + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb); + curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data); + if ($this->size >= 0) + curl_setopt($curl, CURLOPT_BUFFERSIZE, $this->size); + } else + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb); + break; + case 'HEAD': + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD'); + curl_setopt($curl, CURLOPT_NOBODY, true); + break; + case 'DELETE': + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE'); + break; + default: break; + } + + // Execute, grab errors + if (curl_exec($curl)) + $this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE); + else + $this->response->error = array( + 'code' => curl_errno($curl), + 'message' => curl_error($curl), + 'resource' => $this->resource + ); + + @curl_close($curl); + + // Parse body into XML + if ($this->response->error === false && isset($this->response->headers['type']) && + $this->response->headers['type'] == 'application/xml' && isset($this->response->body)) { + $this->response->body = simplexml_load_string($this->response->body); + + // Grab S3 errors + if (!in_array($this->response->code, array(200, 204)) && + isset($this->response->body->Code, $this->response->body->Message)) { + $this->response->error = array( + 'code' => (string)$this->response->body->Code, + 'message' => (string)$this->response->body->Message + ); + if (isset($this->response->body->Resource)) + $this->response->error['resource'] = (string)$this->response->body->Resource; + unset($this->response->body); + } + } + + // Clean up file resources + if ($this->fp !== false && is_resource($this->fp)) fclose($this->fp); + + return $this->response; + } + + + /** + * CURL write callback + * + * @param resource &$curl CURL resource + * @param string &$data Data + * @return integer + */ + private function __responseWriteCallback(&$curl, &$data) { + if ($this->response->code == 200 && $this->fp !== false) + return fwrite($this->fp, $data); + else + $this->response->body .= $data; + return strlen($data); + } + + + /** + * CURL header callback + * + * @param resource &$curl CURL resource + * @param string &$data Data + * @return integer + */ + private function __responseHeaderCallback(&$curl, &$data) { + if (($strlen = strlen($data)) <= 2) return $strlen; + if (substr($data, 0, 4) == 'HTTP') + $this->response->code = (int)substr($data, 9, 3); + else { + list($header, $value) = explode(': ', trim($data), 2); + if ($header == 'Last-Modified') + $this->response->headers['time'] = strtotime($value); + elseif ($header == 'Content-Length') + $this->response->headers['size'] = (int)$value; + elseif ($header == 'Content-Type') + $this->response->headers['type'] = $value; + elseif ($header == 'ETag') + $this->response->headers['hash'] = $value{0} == '"' ? substr($value, 1, -1) : $value; + elseif (preg_match('/^x-amz-meta-.*$/', $header)) + $this->response->headers[$header] = is_numeric($value) ? (int)$value : $value; + } + return $strlen; + } + +} diff --git a/3.0/modules/aws_s3/models/MY_Item_Model.php b/3.0/modules/aws_s3/models/MY_Item_Model.php new file mode 100644 index 00000000..1ef443f2 --- /dev/null +++ b/3.0/modules/aws_s3/models/MY_Item_Model.php @@ -0,0 +1,90 @@ +s3_thumb_uploaded) + return parent::thumb_url($full_uri); + + if ($this->is_photo()) + return aws_s3::generate_url("th/" . $this->relative_path(), ($this->view_1 == 1 ? false : true), $this->updated); + else if ($this->is_album() && $this->id > 1) + return aws_s3::generate_url("th/" . $this->relative_path() . "/.album.jpg", ($this->view_1 == 1 ? false : true), $this->updated); + else if ($this->is_movie()) + return aws_s3::generate_url("th/" . preg_replace("/...$/", "jpg", $this->relative_path()), ($this->view_1 == 1 ? false : true), $this->updated); + } + + public function file_url($full_uri=false) { + if (!module::get_var("aws_s3", "enabled") || Router::$controller == "rest" || !$this->s3_fullsize_uploaded) + return parent::file_url($full_uri); + + return aws_s3::generate_url("fs/" . $this->relative_path(), ($this->view_1 == 1 ? false : true), $this->updated); + } + + public function resize_url($full_uri=false) { + if (!module::get_var("aws_s3", "enabled") || Router::$controller == "rest" || !$this->s3_resize_uploaded) + return parent::resize_url($full_uri); + + if ($this->is_album() && $this->id > 1) + return aws_s3::generate_url("rs/" . $this->relative_path() . "/.album.jpg", ($this->view_1 == 1 ? false : true), $this->updated); + else + return aws_s3::generate_url("rs/" . $this->relative_path(), ($this->view_1 == 1 ? false : true), $this->updated); + } + + private function _load_aws_s3_meta($create_if_not_exists = true) { + $this->_aws_s3_meta = ORM::factory("aws_s3_meta")->find($this->id); + if (!$this->_aws_s3_meta->item_id) { + if ($create_if_not_exists) { + $this->_aws_s3_meta->item_id = $this->id; + $this->_aws_s3_meta->save(); + } + else + return false; + } + return $this; + } + + public function has_aws_s3_meta() { + if (!$this->_load_aws_s3_meta(false)) + return false; + return true; + } + + public function get_aws_s3_meta() { + if (!$this->_aws_s3_meta) + $this->_load_aws_s3_meta(); + + return $this->_aws_s3_meta; + } + + public function save_s3_meta() { + if ($this->_aws_s3_meta) + $this->_aws_s3_meta->save(); + } + + public function save() { + $this->save_s3_meta(); + return parent::save(); + } + + public function __get($column) { + if (substr($column, 0, 3) == "s3_") { + $var = substr($column, 3); + return $this->get_aws_s3_meta()->$var; + } + return parent::__get($column); + } + + public function __set($column, $value) { + if (substr($column, 0, 3) == "s3_") { + $var = substr($column, 3); + $this->get_aws_s3_meta()->$var = $value; + } + else { + parent::__set($column, $value); + } + } + +} \ No newline at end of file diff --git a/3.0/modules/aws_s3/models/aws_s3_meta.php b/3.0/modules/aws_s3/models/aws_s3_meta.php new file mode 100644 index 00000000..7010c595 --- /dev/null +++ b/3.0/modules/aws_s3/models/aws_s3_meta.php @@ -0,0 +1,6 @@ + S3 file transfers diff --git a/3.0/modules/aws_s3/views/admin_aws_s3.html.php b/3.0/modules/aws_s3/views/admin_aws_s3.html.php new file mode 100644 index 00000000..05d340de --- /dev/null +++ b/3.0/modules/aws_s3/views/admin_aws_s3.html.php @@ -0,0 +1,16 @@ + + +
      + +

      + +

      + +

      donating to help support future development."); ?> + +

      + +
      +
      + + diff --git a/3.0/modules/basket/helpers/basket_theme.php b/3.0/modules/basket/helpers/basket_theme.php index 1ad535e5..db2c91da 100644 --- a/3.0/modules/basket/helpers/basket_theme.php +++ b/3.0/modules/basket/helpers/basket_theme.php @@ -20,7 +20,7 @@ class basket_theme_Core { static function head($theme) { - $theme->css("basket.css"); + return $theme->css("basket.css"); } static function header_top($theme) { diff --git a/3.0/modules/batchtag/controllers/batchtag.php b/3.0/modules/batchtag/controllers/batchtag.php index ec012719..01f2e7ff 100644 --- a/3.0/modules/batchtag/controllers/batchtag.php +++ b/3.0/modules/batchtag/controllers/batchtag.php @@ -1,7 +1,7 @@ post('name')}&item_id={$input->post('item_id')}&tag_subitems={$input->post('tag_subitems')}&csrf={$input->post('csrf')}")); + } + + public function tagitems2() { + // Tag all non-album items in the current album with the specified tags. + + // Prevent Cross Site Request Forgery + access::verify_csrf(); + + $input = Input::instance(); + + // Variables + if (($input->get("batchtag_max") == false) || ($input->get("batchtag_max") == "0")) { + $batchtag_max = "50"; + } else { + $batchtag_max = $input->get("batchtag_max"); + } + if ($input->get("batchtag_items_processed") == false) { + $batchtag_items_processed = "0"; + } else { + $batchtag_items_processed = $input->get("batchtag_items_processed"); + } + // Figure out if the contents of sub-albums should also be tagged - $str_tag_subitems = $input->post("tag_subitems"); + $str_tag_subitems = $input->get("tag_subitems"); $children = ""; if ($str_tag_subitems == false) { // Generate an array of all non-album items in the current album. $children = ORM::factory("item") - ->where("parent_id", "=", $input->post("item_id")) + ->where("parent_id", "=", $input->get("item_id")) ->where("type", "!=", "album") ->find_all(); } else { // Generate an array of all non-album items in the current album // and any sub albums. - $item = ORM::factory("item", $input->post("item_id")); + $item = ORM::factory("item", $input->get("item_id")); $children = $item->descendants(); } + // Loop through each item in the album and make sure the user has // access to view and edit it. - foreach ($children as $child) { - if (access::can("view", $child) && access::can("edit", $child) && !$child->is_album()) { + $children_count = "0"; + $tag_count = "0"; - // Assuming the user can view/edit the current item, loop - // through each tag that was submitted and apply it to - // the current item. - foreach (explode(",", $input->post("name")) as $tag_name) { - $tag_name = trim($tag_name); - if ($tag_name) { - tag::add($child, $tag_name); + //echo Kohana::debug($children); + + echo ''; + + foreach ($children as $child) { + + if ($tag_count < $batchtag_max) { + + if ($children_count >= $batchtag_items_processed) { + if (access::can("view", $child) && access::can("edit", $child) && !$child->is_album()) { + + // Assuming the user can view/edit the current item, loop + // through each tag that was submitted and apply it to + // the current item. + foreach (explode(",", $input->get("name")) as $tag_name) { + $tag_name = trim($tag_name); + if ($tag_name) { + tag::add($child, $tag_name); + } + // $tag_count should be inside the foreach loop as it is depending on the number of time tag:add is run + $tag_count++; + } } - } - } + echo '' . "\n"; + $children_count++; + $batchtag_max_new = $tag_count; + echo ''; + } else { $children_count++; } + + } else { break; } + } - // Redirect back to the album. - $item = ORM::factory("item", $input->post("item_id")); - url::redirect(url::abs_site("{$item->type}s/{$item->id}")); + if ($tag_count < $batchtag_max) { + // Redirect back to the album. + $item = ORM::factory("item", $input->get("item_id")); + url::redirect(url::abs_site("{$item->type}s/{$item->id}")); + //echo url::abs_site("{$item->type}s/{$item->id}"); + } else { + url::redirect(url::abs_site("batchtag/tagitems2?name={$input->get('name')}&item_id={$input->get('item_id')}&tag_subitems={$input->get('tag_subitems')}&batchtag_items_processed=$children_count&batchtag_max=$batchtag_max&csrf={$input->get('csrf')}")); + //echo url::abs_site("batchtag/tagitems2?name={$input->get('name')}&item_id={$input->get('item_id')}&tag_subitems={$input->get('tag_subitems')}&batchtag_items_processed=$children_count&batchtag_max=$batchtag_max&csrf={$input->get('csrf')}"); + } } } diff --git a/3.0/modules/batchtag/helpers/batchtag_block.php b/3.0/modules/batchtag/helpers/batchtag_block.php index f1be1387..01fe1216 100644 --- a/3.0/modules/batchtag/helpers/batchtag_block.php +++ b/3.0/modules/batchtag/helpers/batchtag_block.php @@ -1,7 +1,7 @@ css("calendarview_menu.css"); + return $theme->css("calendarview_menu.css"); } } diff --git a/3.0/modules/calendarview/libraries/Calendar_Breadcrumb.php b/3.0/modules/calendarview/libraries/Calendar_Breadcrumb.php index 60502667..751af272 100644 --- a/3.0/modules/calendarview/libraries/Calendar_Breadcrumb.php +++ b/3.0/modules/calendarview/libraries/Calendar_Breadcrumb.php @@ -1,7 +1,7 @@ content = new View("captionator_dialog.html"); $v->content->album = $album; + $v->content->enable_tags = module::is_active("tag"); + if ($v->content->enable_tags) { + $v->content->tags = array(); + foreach ($album->viewable()->children() as $child) { + $item = ORM::factory("item", $child->id); + $tag_names = array(); + foreach (tag::item_tags($item) as $tag) { + $tag_names[] = $tag->name; + } + $v->content->tags[$child->id] = implode(", ", $tag_names); + } + } print $v; } @@ -42,12 +54,27 @@ class Captionator_Controller extends Controller { if (Input::instance()->post("save")) { $titles = Input::instance()->post("title"); $descriptions = Input::instance()->post("description"); + $filenames = Input::instance()->post("filename"); + $internetaddresses = Input::instance()->post("internetaddress"); + $tags = Input::instance()->post("tags"); + $enable_tags = module::is_active("tag"); foreach (array_keys($titles) as $id) { $item = ORM::factory("item", $id); if ($item->loaded() && access::can("edit", $item)) { $item->title = $titles[$id]; $item->description = $descriptions[$id]; + $item->name = $filenames[$id]; + $item->slug = $internetaddresses[$id]; $item->save(); + if ($enable_tags) { + tag::clear_all($item); + foreach (explode(",", $tags[$id]) as $tag_name) { + if ($tag_name) { + tag::add($item, trim($tag_name)); + } + } + tag::compact(); + } } } message::success(t("Captions saved")); diff --git a/3.0/modules/captionator/helpers/captionator_event.php b/3.0/modules/captionator/helpers/captionator_event.php index d00c04ae..43e501f8 100644 --- a/3.0/modules/captionator/helpers/captionator_event.php +++ b/3.0/modules/captionator/helpers/captionator_event.php @@ -1,7 +1,7 @@
      +
      id}") ?>" method="post" id="g-captionator-form">
      @@ -23,6 +29,20 @@
    • + +
    • + + +
    • + +
    • + + +
    • +
    • + + +
    diff --git a/3.0/modules/contactowner/controllers/admin_contactowner.php b/3.0/modules/contactowner/controllers/admin_contactowner.php index 73a82ee3..26b684ab 100644 --- a/3.0/modules/contactowner/controllers/admin_contactowner.php +++ b/3.0/modules/contactowner/controllers/admin_contactowner.php @@ -1,7 +1,7 @@ /** * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2010 Bharat Mediratta + * Copyright (C) 2000-2011 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/3.0/modules/developer/views/block.txt.php b/3.0/modules/developer/views/block.txt.php index aae11c89..28a8d9db 100644 --- a/3.0/modules/developer/views/block.txt.php +++ b/3.0/modules/developer/views/block.txt.php @@ -3,7 +3,7 @@ /** * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2010 Bharat Mediratta + * Copyright (C) 2000-2011 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/3.0/modules/developer/views/controller.txt.php b/3.0/modules/developer/views/controller.txt.php index b73ae815..664ff987 100644 --- a/3.0/modules/developer/views/controller.txt.php +++ b/3.0/modules/developer/views/controller.txt.php @@ -2,7 +2,7 @@ /** * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2010 Bharat Mediratta + * Copyright (C) 2000-2011 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/3.0/modules/developer/views/event.txt.php b/3.0/modules/developer/views/event.txt.php index ac5db4e3..32a48520 100644 --- a/3.0/modules/developer/views/event.txt.php +++ b/3.0/modules/developer/views/event.txt.php @@ -2,7 +2,7 @@ /** * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2010 Bharat Mediratta + * Copyright (C) 2000-2011 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/3.0/modules/developer/views/installer.txt.php b/3.0/modules/developer/views/installer.txt.php index 6748ac46..cf6662d5 100644 --- a/3.0/modules/developer/views/installer.txt.php +++ b/3.0/modules/developer/views/installer.txt.php @@ -2,7 +2,7 @@ /** * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2010 Bharat Mediratta + * Copyright (C) 2000-2011 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/3.0/modules/developer/views/theme.txt.php b/3.0/modules/developer/views/theme.txt.php index 190ff828..e4467f43 100644 --- a/3.0/modules/developer/views/theme.txt.php +++ b/3.0/modules/developer/views/theme.txt.php @@ -2,7 +2,7 @@ /** * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2010 Bharat Mediratta + * Copyright (C) 2000-2011 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/3.0/modules/displaytags/helpers/displaytags_block.php b/3.0/modules/displaytags/helpers/displaytags_block.php index ea63bb77..8fc530f1 100644 --- a/3.0/modules/displaytags/helpers/displaytags_block.php +++ b/3.0/modules/displaytags/helpers/displaytags_block.php @@ -1,7 +1,7 @@ is_album()) { - exif::extract($item); +class displaytags_event_Core { + static function pre_deactivate($data) { + if ($data->module == "tag") { + $data->messages["warn"][] = t("The DisplayTags module requires the Tags module."); } } - static function item_deleted($item) { - db::build() - ->delete("exif_records") - ->where("item_id", "=", $item->id) - ->execute(); - } - - static function photo_menu($menu, $theme) { - $item = $theme->item(); - $menu->append( - Menu::factory("link") - ->id("exifdata-link") - ->label(t("Photo Details")) - ->url(url::site("exif/show/$item->id")) - ->css_id("g-exifdata-link")); + static function module_change($changes) { + if (!module::is_active("tag") || in_array("tag", $changes->deactivate)) { + site_status::warning( + t("The DisplayTags module requires the Tags module. Activate the Tags module now", + array("url" => html::mark_clean(url::site("admin/modules")))), + "displaytags_needs_tag"); + } else { + site_status::clear("displaytags_needs_tag"); + } } } diff --git a/3.0/themes/greydragon/helpers/greydragon_installer.php b/3.0/modules/displaytags/helpers/displaytags_installer.php similarity index 66% rename from 3.0/themes/greydragon/helpers/greydragon_installer.php rename to 3.0/modules/displaytags/helpers/displaytags_installer.php index 461e6914..808def8a 100644 --- a/3.0/themes/greydragon/helpers/greydragon_installer.php +++ b/3.0/modules/displaytags/helpers/displaytags_installer.php @@ -1,30 +1,36 @@ - \ No newline at end of file +> 8) + (($hash & 0xff000000) >> 24) - : $hash; + $output = $hash; + + if( version_compare(PHP_VERSION, '5.2.7', '<') ) { + $str = str_pad(dechex($hash), 8, '0', STR_PAD_LEFT); + $output = hexdec($str{6}.$str{7}.$str{4}.$str{5}.$str{2}.$str{3}.$str{0}.$str{1}); + } + + return $output; } } diff --git a/3.0/modules/downloadalbum/helpers/downloadalbum_event.php b/3.0/modules/downloadalbum/helpers/downloadalbum_event.php index e58512ac..e8159003 100644 --- a/3.0/modules/downloadalbum/helpers/downloadalbum_event.php +++ b/3.0/modules/downloadalbum/helpers/downloadalbum_event.php @@ -1,7 +1,7 @@ css("downloadalbum_menu.css"); + return $theme->css("downloadalbum_menu.css"); } } diff --git a/3.0/modules/downloadfullsize/controllers/admin_downloadfullsize.php b/3.0/modules/downloadfullsize/controllers/admin_downloadfullsize.php index 1b55bd5c..6836c9c8 100644 --- a/3.0/modules/downloadfullsize/controllers/admin_downloadfullsize.php +++ b/3.0/modules/downloadfullsize/controllers/admin_downloadfullsize.php @@ -1,7 +1,7 @@ item && access::can("view_full", $theme->item)) { - $theme->css("downloadfullsize_menu.css"); + return $theme->css("downloadfullsize_menu.css"); } } } diff --git a/3.0/modules/dynamic/controllers/admin_dynamic.php b/3.0/modules/dynamic/controllers/admin_dynamic.php index 0180fef3..0f87329f 100644 --- a/3.0/modules/dynamic/controllers/admin_dynamic.php +++ b/3.0/modules/dynamic/controllers/admin_dynamic.php @@ -1,6 +1,6 @@ _get_admin_form(); if ($form->validate()) { - module::set_var("ecard", "sender", $form->ecard->sender->value); + module::set_var("ecard","send_plain",$form->ecard->send_plain->value); + module::set_var("ecard", "sender", $form->ecard->sender->value); module::set_var("ecard", "bcc", $form->ecard->bcc->value); module::set_var("ecard", "subject", $form->ecard->subject->value); module::set_var("ecard", "message", $form->ecard->message->value); + module::set_var("ecard", "max_length", $form->ecard->max_length->value); module::set_var("ecard", "access_permissions", $form->ecard->access_permissions->value); module::set_var("ecard", "location", $form->ecard->location->value); message::success(t("eCard settings updated")); @@ -54,9 +56,18 @@ class Admin_ecard_Controller extends Admin_Controller { ->value(module::get_var("ecard", "bcc", "")); $ecard_settings->input("subject")->label(t("E-mail subject")) ->value(module::get_var("ecard", "subject")); - $ecard_settings->textarea("message")->label(t("E-mail message. Valid keywords are \"%toname\" (recipient's name) and \"%fromname\" (sender's name))")) + $ecard_settings->textarea("message")->label(t("E-mail message. Valid keywords are \"%fromname\" (sender's name))")) ->value(module::get_var("ecard", "message")); - $ecard_settings->dropdown("access_permissions") + $ecard_settings->input("max_length") + ->label(t("Maximum message length")) + ->value(module::get_var("ecard","max_length")); + if(module::is_active("watermark")) { + $ecard_settings->checkbox("send_plain") + ->label(t("Allow users to send non-watermarked versions")) + ->value(true) + ->checked(module::get_var("ecard","send_plain")); + } + $ecard_settings->dropdown("access_permissions") ->label(t("Who can send eCards?")) ->options(array("everybody" => t("Everybody"), "registered_users" => t("Only registered users"))) diff --git a/3.0/modules/ecard/controllers/ecard.php b/3.0/modules/ecard/controllers/ecard.php index 6ca30df7..82777443 100644 --- a/3.0/modules/ecard/controllers/ecard.php +++ b/3.0/modules/ecard/controllers/ecard.php @@ -1,7 +1,7 @@ item = $item; - $v->subject = module::get_var("ecard", "subject"); - $to_name = $form->send_ecard->to_name->value; - $from_name = $form->send_ecard->from_name->value; - $bcc = module::get_var("ecard", "bcc"); - $v->message = t(module::get_var("ecard", "message"), array("toname" => $to_name, "fromname" => $from_name)); - $v->custom_message = $form->send_ecard->text->value; - $v->image = $item->name; - $to = $form->send_ecard->inputs["to_email"]->value; - $from = $form->send_ecard->inputs["from_email"]->value; - $headers = array("from" => $from_name."<".$from.">", "to" => $to, "subject" => module::get_var("ecard", "subject")); - require_once(MODPATH. "ecard/lib/mime.php"); - $mime = new Mail_mime("\n"); - $mime->setHTMLBody($v->render()); - $mime->addHTMLImage($item->resize_path(),$item->mime_type,$item->name); - $body = $mime->get(array('html_charset' => 'UTF-8', 'text_charset' => 'UTF-8','text_encoding' => '8bit','head_charset' => 'UTF-8')); - self::_notify($headers['to'], $headers['from'], $headers['subject'], $item, $body, $mime->headers(), $bcc); + $to_array = explode(",",$form->send_ecard->inputs["to_email"]->value); + foreach($to_array as $to) { + $v = new View("ecard_email.html"); + $v->item = $item; + $v->subject = module::get_var("ecard", "subject"); + $from_name = $form->send_ecard->from_name->value; + $bcc = module::get_var("ecard", "bcc"); + if($form->send_ecard->send_to_self->checked == true) { + $cc = $form->send_ecard->inputs["from_email"]->value; + } + $v->message = t(module::get_var("ecard", "message"), array("fromname" => $from_name)); + $v->custom_message = $form->send_ecard->text->value; + $v->image = $item->name; + $from = $form->send_ecard->inputs["from_email"]->value; + $headers = array("from" => $from_name."<".$from.">", "to" => $to, "subject" => module::get_var("ecard", "subject")); + require_once(MODPATH. "ecard/lib/mime.php"); + $mime = new Mail_mime("\n"); + $mime->setHTMLBody($v->render()); + if($form->send_ecard->send_fresh->checked == true) { + $tmpfile = tempnam(TMPPATH, "clean"); + if($form->send_ecard->send_thumbnail->checked == true) { + $options = array("width" => module::get_var("gallery", "thumb_size"), "height" => module::get_var("gallery", "thumb_size"), "master" => Image::AUTO); + gallery_graphics::resize($item->file_path(), $tmpfile, $options); + $mime->addHTMLImage($tmpfile,$item->mime_type,$item->name); + } else { + $options = array("width" => module::get_var("gallery", "resize_size"), "height" => module::get_var("gallery", "resize_size"), "master" => Image::AUTO); + gallery_graphics::resize($item->file_path(), $tmpfile, $options); + $mime->addHTMLImage($tmpfile,$item->mime_type,$item->name); + } + } else { + if($form->send_ecard->send_thumbnail->checked == true) { + $mime->addHTMLImage($item->thumb_path(),$item->mime_type,$item->name); + } else { + $mime->addHTMLImage($item->resize_path(),$item->mime_type,$item->name); + } + } + $body = $mime->get(array('html_charset' => 'UTF-8', 'text_charset' => 'UTF-8','text_encoding' => '8bit','head_charset' => 'UTF-8')); + self::_notify($headers['to'], $headers['from'], $headers['subject'], $item, $body, $mime->headers(), $bcc, $cc); + } + unlink($tmpfile); message::success("eCard successfully sent"); json::reply(array("result" => "success")); - } else { + } else { json::reply(array("result" => "error", "html" => (string) $form)); - } + } } /** * Present a form for sending a new ecard. @@ -73,9 +95,11 @@ class Ecard_Controller extends Controller { if (!ecard::can_send_ecard()) { access::forbidden(); } - print ecard::prefill_send_form(ecard::get_send_form($item)); + $v_form = new View("ecard_form.html"); + $v_form->item_id = $item_id; + print $v_form->render(); } - private static function _notify($to, $from, $subject, $item, $text, $headers, $bcc) { + private static function _notify($to, $from, $subject, $item, $text, $headers, $bcc, $cc) { $sendmail = Sendmail::factory(); $sendmail ->to($to) @@ -84,6 +108,9 @@ class Ecard_Controller extends Controller { if(isset($bcc)) { $sendmail->header("bcc",$bcc); } + if(isset($cc)) { + $sendmail->header("cc",$cc); + } foreach($headers as $key => $value) { $sendmail->header($key,$value); } diff --git a/3.0/modules/ecard/helpers/ecard.php b/3.0/modules/ecard/helpers/ecard.php index 13485954..a786521b 100644 --- a/3.0/modules/ecard/helpers/ecard.php +++ b/3.0/modules/ecard/helpers/ecard.php @@ -1,7 +1,7 @@ id}", "", "post", array("id" => "g-ecard-form")); + static function get_send_form($item_id) { + $form = new Forge("ecard/send/{$item_id}", "", "post", array("id" => "g-ecard-form")); $group = $form->group("send_ecard")->label(t("Send eCard")); $group->input("from_name") ->label(t("Your name")) @@ -38,23 +38,32 @@ class ecard_Core { ->rules("required|valid_email") ->error_messages("required", t("You must enter a valid email address")) ->error_messages("invalid", t("You must enter a valid email address")); - $group->input("to_name") - ->label(t("Recipient's Name")) - ->id("g-recipient") - ->rules("required") - ->error_messages("required", t("You must enter a recipient's name")); $group->input("to_email") - ->label(t("Recipient's e-mail")) + ->label(t("Recipient's e-mail. Separate multiple recipients with a comma.")) ->id("g-recip-email") - ->rules("required|valid_email") - ->error_messages("required", t("You must enter a valid email address")) - ->error_messages("invalid", t("You must enter a valid email address")); + ->rules("required") + ->error_messages("required", t("You must enter a valid email address")); $group->textarea("text") - ->label(t("Message")) + ->label(t("Message (".module::get_var("ecard","max_length")." chars max)")) ->id("g-text") + ->maxlength(module::get_var("ecard","max_length")) ->rules("required") ->error_messages("required", t("You must enter a message")); - $group->hidden("item_id")->value($item->id); + $group->checkbox("send_to_self") + ->label(t("Send yourself a copy")) + ->value(true) + ->checked(false); + $group->checkbox("send_thumbnail") + ->label(t("Send thumbnail image, instead of resized image.")) + ->value(true) + ->checked(false); + if(module::get_var("ecard","send_plain") == true && module::is_active("watermark")) { + $group->checkbox("send_fresh") + ->label(t("Send non-watermarked image.")) + ->value(true) + ->checked(false); + } + $group->hidden("item_id")->value($item_id); module::event("ecard_send_form", $form); module::event("captcha_protect_form", $form); $group->submit("")->value(t("Send"))->class("ui-state-default ui-corner-all"); diff --git a/3.0/modules/ecard/helpers/ecard_block.php b/3.0/modules/ecard/helpers/ecard_block.php index 051c55c6..d90755ab 100644 --- a/3.0/modules/ecard/helpers/ecard_block.php +++ b/3.0/modules/ecard/helpers/ecard_block.php @@ -1,7 +1,7 @@ item() && $theme->item()->is_photo() && module::get_var("ecard", "location") == "sidebar") { $block = new Block(); - $block->css_id = "g-send-ecard"; + $block->css_id = "g-sendecard"; $block->title = t("eCard"); $block->content = new View("ecard_block.html"); } diff --git a/3.0/modules/ecard/helpers/ecard_event.php b/3.0/modules/ecard/helpers/ecard_event.php index 06165b8f..ebbd5442 100644 --- a/3.0/modules/ecard/helpers/ecard_event.php +++ b/3.0/modules/ecard/helpers/ecard_event.php @@ -1,7 +1,7 @@ css("ecard.css"); + return $theme->css("ecard.css"); } } \ No newline at end of file diff --git a/3.0/modules/ecard/module.info b/3.0/modules/ecard/module.info index 95c8f6a4..d5b27c70 100644 --- a/3.0/modules/ecard/module.info +++ b/3.0/modules/ecard/module.info @@ -1,4 +1,3 @@ name = "E-Card" description = "Send a photo as a postcard" -version = 4 - +version = 11 diff --git a/3.0/modules/ecard/views/ecard_block.html.php b/3.0/modules/ecard/views/ecard_block.html.php index 3f307a1d..d8aa4e4e 100644 --- a/3.0/modules/ecard/views/ecard_block.html.php +++ b/3.0/modules/ecard/views/ecard_block.html.php @@ -1,6 +1,6 @@ -id}") ?>" id="g-send-ecard" +id}") ?>" class="g-dialog-link g-button ui-state-default ui-corner-all"> - + diff --git a/3.0/modules/ecard/views/ecard_form.html.php b/3.0/modules/ecard/views/ecard_form.html.php new file mode 100644 index 00000000..fc22e95b --- /dev/null +++ b/3.0/modules/ecard/views/ecard_form.html.php @@ -0,0 +1 @@ + Send eCard \ No newline at end of file diff --git a/3.0/modules/editcreation/helpers/editcreation_event.php b/3.0/modules/editcreation/helpers/editcreation_event.php index c76e730d..8820d8fa 100644 --- a/3.0/modules/editcreation/helpers/editcreation_event.php +++ b/3.0/modules/editcreation/helpers/editcreation_event.php @@ -1,7 +1,7 @@ item(); if ( $item && access::can("edit", $item) ) { - $theme->css("editcreation.css"); + return $theme->css("editcreation.css"); } } } diff --git a/3.0/modules/embed_videos/controllers/embedded_videos.php b/3.0/modules/embed_videos/controllers/embedded_videos.php index 6c86e3a0..fc7281f2 100644 --- a/3.0/modules/embed_videos/controllers/embedded_videos.php +++ b/3.0/modules/embed_videos/controllers/embedded_videos.php @@ -1,7 +1,7 @@ order_by("exif_coordinates.latitude", "ASC") ->descendants(); $curr_album = ORM::factory("item")->where("id", "=", $type_id)->find_all(); - $map_title = $curr_album[0]->name; + $map_title = $curr_album[0]->title; } elseif ($map_type == "user") { // Generate an array of all items uploaded by the current user that // have exif gps coordinates and order by latitude (to group items diff --git a/3.0/modules/exif_gps/helpers/exif_gps.php b/3.0/modules/exif_gps/helpers/exif_gps.php index d3440424..823b4b29 100644 --- a/3.0/modules/exif_gps/helpers/exif_gps.php +++ b/3.0/modules/exif_gps/helpers/exif_gps.php @@ -1,7 +1,7 @@ get("completed"); // Generate an array of the next 100 photos to check. - $all_photos = ORM::factory("item") - ->where("id", ">", $last_id) - ->where("type", "=", "photo") - ->find_all(100); + //$all_photos = ORM::factory("item") + // ->where("id", ">", $last_id) + // ->where("type", "=", "photo") + // ->order_by("id") + // ->find_all(100); // Check each photo in the array to see if it already has exif gps data associated with it. // If it doesn't, attempt to extract gps coordinates. foreach (ORM::factory("item") ->where("id", ">", $last_id) ->where("type", "=", "photo") + ->order_by("id") ->find_all(100) as $item) { $record = ORM::factory("exif_coordinate")->where("item_id", "=", $item->id)->find(); diff --git a/3.0/modules/exif_gps/helpers/exif_gps_theme.php b/3.0/modules/exif_gps/helpers/exif_gps_theme.php index 160373a2..90431195 100644 --- a/3.0/modules/exif_gps/helpers/exif_gps_theme.php +++ b/3.0/modules/exif_gps/helpers/exif_gps_theme.php @@ -1,7 +1,7 @@ css("exif_gps_menu.css"); + return $theme->css("exif_gps_menu.css"); } } diff --git a/3.0/modules/exif_gps/models/exif_coordinate.php b/3.0/modules/exif_gps/models/exif_coordinate.php index 481da1cd..e3286d93 100644 --- a/3.0/modules/exif_gps/models/exif_coordinate.php +++ b/3.0/modules/exif_gps/models/exif_coordinate.php @@ -1,7 +1,7 @@ css("favourites.css"); - $theme->script("favourites.js"); + return $theme->css("favourites.css") + . $theme->script("favourites.js"); } static function header_top($theme) { diff --git a/3.0/modules/google_analytics/controllers/admin_google_analytics.php b/3.0/modules/google_analytics/controllers/admin_google_analytics.php index 84b7daeb..4a28ad8d 100644 --- a/3.0/modules/google_analytics/controllers/admin_google_analytics.php +++ b/3.0/modules/google_analytics/controllers/admin_google_analytics.php @@ -1,7 +1,7 @@ script("highroller.js"); - printf("", url::site("highroller/pick_theme")); + return $theme->script("highroller.js") + . sprintf("", url::site("highroller/pick_theme")); } static function header_top($theme) { diff --git a/3.0/modules/html_uploader/controllers/uploader.php b/3.0/modules/html_uploader/controllers/uploader.php index 78c64468..0b9b5351 100644 --- a/3.0/modules/html_uploader/controllers/uploader.php +++ b/3.0/modules/html_uploader/controllers/uploader.php @@ -1,7 +1,7 @@ script("kbd_nav.js"); - } -} \ No newline at end of file diff --git a/3.0/modules/kbd_nav/js/kbd_nav.js b/3.0/modules/kbd_nav/js/kbd_nav.js deleted file mode 100644 index 25eb7210..00000000 --- a/3.0/modules/kbd_nav/js/kbd_nav.js +++ /dev/null @@ -1,102 +0,0 @@ -/** -* -* Copyright (c) 2010 Serguei Dosyukov, http://blog.dragonsoft.us -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation -* files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, -* modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*/ - -$.fn.KbdNavigation = function(options, callback) { - - this.options = options || {}; - var opt = this.options; - this.callback = callback || null; - var clbk = this.callback; - - $(this).bind("keydown", function(event) { - if ($('#sb-body-inner>img#sb-content').is(':visible')) { - return false; - } - // ignore shortcuts when inside a jQuery dialog; otherwise it becomes impossible - // to navigate the cursor inside an input box - if ($('.ui-widget-overlay').is(':visible')) { - return true; - } - - var direction = "ltr"; - if (document.body) { - if (window.getComputedStyle) { - direction = window.getComputedStyle(document.body, null).direction; - } else if (document.body.currentStyle) { - direction = document.body.currentStyle.direction; - } - } - - var lnk = ""; - var lnk_first, lnk_prev, lnk_parent, lnk_next, lnk_last; - - if(opt.first) { lnk_first = opt.first; } else { lnk_first = $("#g-navi-first").attr("href"); } - if(opt.prev) { lnk_prev = opt.prev; } else { lnk_prev = $("#g-navi-prev").attr("href"); } - if(opt.parent) { lnk_parent = opt.parent; } else { lnk_parent = $("#g-navi-parent").attr("href"); } - if(opt.next) { lnk_next = opt.next; } else { lnk_next = $("#g-navi-next").attr("href"); } - if(opt.last) { lnk_last = opt.last; } else { lnk_last = $("#g-navi-last").attr("href"); } - - // Support for standard Wind Theme tags - if(!lnk_first) { lnk_first = $(".g-paginator .ui-icon-seek-first").parent().attr("href"); } - if(!lnk_prev) { lnk_prev = $(".g-paginator .ui-icon-seek-prev").parent().attr("href"); } - if(!lnk_next) { lnk_next = $(".g-paginator .ui-icon-seek-next").parent().attr("href"); } - if(!lnk_last) { lnk_last = $(".g-paginator .ui-icon-seek-end").parent().attr("href"); } - - var keyCode = event.keyCode; - - if (direction == "rtl") { - switch(keyCode) { - case 0x25: // Left - keyCode = 0x27; - break; - case 0x27: // Right - keyCode = 0x25; - break; - } - } - - switch(keyCode) { - case 0x25: // Ctr+Left/Left - if(event.ctrlKey) { lnk = lnk_first; } else { lnk = lnk_prev; } - break; - case 0x26: // Ctrl+Up - if(event.ctrlKey) { lnk = lnk_parent; } - break; - case 0x27: // Ctrl+Right/Right - if(event.ctrlKey) { lnk = lnk_last; } else { lnk = lnk_next; } - break; - } - - if(lnk) { - if(typeof clbk == 'function') { - clbk(); - return false; - } else { - window.location = lnk; - return true; - } - } - - return true; - }); -} - -$(document).ready( function() { - $(document).KbdNavigation({}); - if ($('#sb-content').is(':visible')) { return true; } -}); diff --git a/3.0/modules/kbd_nav/module.info b/3.0/modules/kbd_nav/module.info deleted file mode 100644 index 2eda7c73..00000000 --- a/3.0/modules/kbd_nav/module.info +++ /dev/null @@ -1,3 +0,0 @@ -name = "Kbd Navigation" -description = "Adds keyboard navigation to the gallery.
    Version 1.5 | By Serguei Dosyukov | Visit plugin Site | Support" -version = 5 diff --git a/3.0/modules/keeporiginal/controllers/keeporiginal.php b/3.0/modules/keeporiginal/controllers/keeporiginal.php index 0bb3aa4f..36f6affe 100644 --- a/3.0/modules/keeporiginal/controllers/keeporiginal.php +++ b/3.0/modules/keeporiginal/controllers/keeporiginal.php @@ -1,7 +1,7 @@ css("language_flags_sidebar.css"); + return $theme->css("language_flags_sidebar.css"); } } diff --git a/3.0/modules/latestalbums/helpers/latestalbums_rss.php b/3.0/modules/latestalbums/helpers/latestalbums_rss.php index 8aca12a7..aa34088c 100644 --- a/3.0/modules/latestalbums/helpers/latestalbums_rss.php +++ b/3.0/modules/latestalbums/helpers/latestalbums_rss.php @@ -1,7 +1,7 @@ "ldap", "allow_updates" => false, "params" => array( - "groups" => array("eng", "google", "guest"), + "groups" => array("engineering", "everybody", "guest"), "everybody_group" => "guest", - "registered_users_group" => "google", - "admins" => array("mediratta", "martinm"), - "url" => "ldaps://ldap.corp.google.com/", - "group_domain" => "ou=Posix,ou=Groups,dc=google,dc=com", - "user_domain" => "ou=People,dc=google,dc=com", + "registered_users_group" => "everybody", + "admins" => array("alice", "bob"), + "url" => "ldaps://ldap.mycompany.com/", + "group_domain" => "ou=Posix,ou=Groups,dc=ymcompany,dc=com", + "user_domain" => "ou=People,dc=MyCompany,dc=com", "bind_rdn" => null, "bind_password" => null, ) diff --git a/3.0/modules/ldap/helpers/ldap_installer.php b/3.0/modules/ldap/helpers/ldap_installer.php index 37269748..d9bdbfd4 100644 --- a/3.0/modules/ldap/helpers/ldap_installer.php +++ b/3.0/modules/ldap/helpers/ldap_installer.php @@ -1,7 +1,7 @@ ldap_entry["displayname"][0]; + if (!empty($this->ldap_entry["displayname"][0])) { + return $this->ldap_entry["displayname"][0]; + } + return $this->ldap_entry["cn"][0]; } public function __get($key) { diff --git a/3.0/modules/metadescription/helpers/metadescription_event.php b/3.0/modules/metadescription/helpers/metadescription_event.php index bde007b0..5fedfa11 100644 --- a/3.0/modules/metadescription/helpers/metadescription_event.php +++ b/3.0/modules/metadescription/helpers/metadescription_event.php @@ -1,7 +1,7 @@ page_title = t("Gallery 3 :: Manage Module Updates"); $view->content = new View("admin_moduleupdates.html"); + $view->content->mu_version = module::get_version("moduleupdates"); - $devDebug = false; - $refreshCache = false; + $refreshCache = false; $cache = unserialize(Cache::instance()->get("moduleupdates_cache")); - $cache_updates = unserialize(Cache::instance()->get("moduleupdates_cache_updates")); - - //--------------------------------------------------------------------------------------------- - //echo 'Message 01: ' .$cache_updates . '
    '; - //--------------------------------------------------------------------------------------------- + $cache_updates = unserialize(Cache::instance()->get("moduleupdates_cache_updates")); //if someone pressed the button to refresh now if (request::method() == "post") { @@ -78,7 +73,6 @@ class Admin_Moduleupdates_Controller extends Admin_Controller { } } catch (Exception $e) { - //echo 'Message: ' .$e->getMessage() . '
    '; } //Check the ability to access the Google $Google = null; @@ -91,71 +85,82 @@ class Admin_Moduleupdates_Controller extends Admin_Controller { } } catch (Exception $e) { - //echo 'Message: ' .$e->getMessage() . '
    '; } + $update_count = 0; + if($refreshCache == true){ foreach (module::available() as $this_module_name => $module_info) { + + $font_color_local = "black"; + $core_version = ''; + $core_server = ''; + $core_dlink = ''; + $font_color_core = "black"; + $contrib_version = ''; + $contrib_server = ''; + $contrib_dlink = ''; + $font_color_contrib = "black"; + $gh_version = ''; + $gh_server = ''; + $gh_dlink = ''; + $font_color_gh = "black"; - //example code for setting cache values - //Cache::instance()->set($key, "$log{$msg}", array("task", "log", "import"), 2592000); - //example delete cache - //Cache::instance()->delete("update_l10n_cache:{$task->id}"); - //example for reading cache - //$log = Cache::instance()->get($key); - $remote_version = ''; - $remote_server = ''; - $update_count = 0; - list ($remote_version, $remote_server) = $this->get_remote_module_version($this_module_name, $devDebug); + $font_color_local = $this->get_local_module_version_color ($module_info->version, $module_info->code_version); + list ($core_version, $core_server) = $this->get_remote_module_version($this_module_name, "CORE"); + $font_color_core = $this->get_module_version_color ($module_info->version, $module_info->code_version, $core_version); + list ($contrib_version, $contrib_server) = $this->get_remote_module_version($this_module_name, "CONTRIB"); + $font_color_contrib = $this->get_module_version_color ($module_info->version, $module_info->code_version, $contrib_version); + list ($gh_version, $gh_server) = $this->get_remote_module_version($this_module_name, "GH"); + $font_color_gh = $this->get_module_version_color ($module_info->version, $module_info->code_version, $gh_version); - $font_color = "black"; - //BLUE - DNE: Does Not Exist, this module was not found - if ($remote_version == "DNE") { - $font_color = "blue"; - //PINK - Your installed version is newer than file version - } else if ($module_info->version != '' and $module_info->code_version < $module_info->version) { - $font_color = "pink"; - //ORANGE - Your file version is newer than the installed version - } else if ($module_info->version != '' and $module_info->code_version > $module_info->version) { - $font_color = "orange"; - //GREEN - Your version is newer than the GitHub - } else if ($remote_version < $module_info->code_version or ($module_info->version != '' - and $remote_version < $module_info->version)) { - $font_color = "green"; - //RED - Your version is older than the GitHub - } else if ($remote_version > $module_info->code_version or ($module_info->version != '' - and $remote_version > $module_info->version)) { - $font_color = "red"; + if($font_color_core == "red" or $font_color_contrib == "red" or $font_color_gh == "red"){ $update_count++; - /* - if($remote_server == "(G3)"){ - $module_info->name = "".$module_info->name.""; - }else if($remote_server == "(G3CC)"){ - $module_info->name = "".$module_info->name.""; - }else if($remote_server == "(brentil)"){ - $module_info->name = "".$module_info->name.""; - } - */ } $module_info->name = "".$module_info->name.""; + if (is_numeric($core_version)) { + if($core_version > $module_info->version) { + $core_dlink = "http://github.com/gallery/gallery3/tree/master/modules/".$this_module_name; + } + } + + if (is_numeric($contrib_version)) { + if($contrib_version > $module_info->version) { + $contrib_dlink = "http://github.com/gallery/gallery3-contrib/tree/master/". + substr_replace(gallery::VERSION,"",strpos(gallery::VERSION," ")) ."/modules/".$this_module_name; + } + } + + if (is_numeric($gh_version)) { + if($gh_version > $module_info->version) { + $this_gm_repo = str_replace(".","",substr_replace(gallery::VERSION,"",strpos(gallery::VERSION," "))); + if($this_gm_repo == "30"){ + $gh_dlink = "http://www.gallerymodules.com/update/".$this_module_name; + } else { + $gh_dlink = "http://www.gallerymodules.com/update".$this_gm_repo."/".$this_module_name; + } + + } + } + //populate the list fo modules and their data $cache->$this_module_name = array ("name" => $module_info->name, "locked" => $module_info->locked, "code_version" => $module_info->code_version, "active" => $module_info->active, "version" => $module_info->version,"description" => $module_info->description, - "remote_version" => $remote_version, "remote_server" => $remote_server, "font_color" => $font_color); + "core_version" => $core_version, "core_server" => $core_server, "font_color_core" => $font_color_core, + "contrib_version" => $contrib_version, "contrib_server" => $contrib_server, "font_color_contrib" => $font_color_contrib, + "gh_version" => $gh_version, "gh_server" => $gh_server, "font_color_gh" => $font_color_gh, + "font_color_local" => $font_color_local, "core_dlink" => $core_dlink, "contrib_dlink" => $contrib_dlink, + "gh_dlink" => $gh_dlink); } //Define right now as YYYY.MM.DD HH:MM with the # of updates that are out of date $cache_updates = array("date" => date("Y.m.d - H:i"), "updates" => $update_count); - - //--------------------------------------------------------------------------------------------- - //echo 'Message 02: ' .$cache_updates . '
    '; - //--------------------------------------------------------------------------------------------- - + //Write out the new data to cache with a 30 day expiration & 0 for update data so it's always present Cache::instance()->set("moduleupdates_cache", serialize($cache), array("ModuleUpdates"), 30*86400); Cache::instance()->set("moduleupdates_cache_updates", serialize($cache_updates), array("ModuleUpdates"), null); @@ -167,12 +172,59 @@ class Admin_Moduleupdates_Controller extends Admin_Controller { $view->content->csrf = access::csrf_token(); $view->content->Google = $Google; $view->content->GitHub = $GitHub; + $view->content->Gallery_Version = substr_replace(gallery::VERSION,"",strpos(gallery::VERSION," ")); print $view; } + /** + * + **/ + private function get_module_version_color ($version, $code_version, $remote_version) { + + $font_color = "black"; + + //BLACK - no module version detected + if ($remote_version == "") { + $font_color = "black"; + //BLUE - DNE: Does Not Exist, this module was not found + } else if ($remote_version == "DNE") { + $font_color = "blue"; + //GREEN - Your version is newer than the GitHub + } else if ($remote_version < $code_version or ($version != '' + and $remote_version < $version)) { + $font_color = "green"; + //RED - Your version is older than the GitHub + } else if ($remote_version > $code_version or ($version != '' + and $remote_version > $version)) { + $font_color = "red"; + } + + return $font_color; + } + + + /** + * + **/ + private function get_local_module_version_color ($version, $code_version) { + + $font_color = "black"; + + //PINK - Your installed version is newer than file version + if ($version != '' and $code_version < $version) { + $font_color = "pink"; + //ORANGE - Your file version is newer than the installed version + } else if ($version != '' and $code_version > $version) { + $font_color = "orange"; + } + + return $font_color; + } + + /** * Parses the known GitHub repositories for new versions of modules. * @@ -182,71 +234,88 @@ class Admin_Moduleupdates_Controller extends Admin_Controller { * * http://github.com/gallery/gallery3 * http://github.com/gallery/gallery3-contrib + * http://www.gallerymodules.com * * @author brentil - * @param String The folder name of the module to search for on the remote GitHub server - * @return Array An array with the remote module version and the server it was found on. + * @param String - The folder name of the module to search for on the remote GitHub server + * @param String - The remote server to check against + * @return Array - An array with the remote module version and the server it was found on. */ - private function get_remote_module_version ($module_name, $devDebug) { + private function get_remote_module_version ($module_name, $server_location) { - $version = 'DNE'; + $version = ''; $server = ''; $file = null; - //For development debug only - if ($devDebug == true){ - if ($file == null) { - try { - $file = fopen ("http://github.com/brentil/gallery3-contrib/raw/master/3.0/modules/".$module_name."/module.info", "r"); - if ($file != null) { - $server = '(brentil)'; + switch ($server_location) { + case "CONTRIB": + //Check the Gallery3 Community Contributions GitHub + if ($file == null) { + try { + $file = fopen ("http://github.com/gallery/gallery3-contrib/raw/master/". + substr_replace(gallery::VERSION,"",strpos(gallery::VERSION," "))."/modules/".$module_name."/module.info", "r"); + if ($file != null) { + $server = '(GCC)'; + } + } + catch (Exception $e) { + } } - } - catch (Exception $e) { - //echo 'Message: ' .$e->getMessage() . '
    '; - } - } - } - - //Check the main Gallery3 GitHub - if ($file == null) { - try { - $file = fopen ("http://github.com/gallery/gallery3/raw/master/modules/".$module_name."/module.info", "r"); - if ($file != null) { - $server = '(G3)'; - } - } - catch (Exception $e) { - //echo 'Message: ' .$e->getMessage() . '
    '; - } + break; + case "CORE": + //Check the main Gallery3 GitHub + if ($file == null) { + try { + $file = fopen ("http://github.com/gallery/gallery3/raw/master/modules/".$module_name."/module.info", "r"); + if ($file != null) { + $server = '(G)'; + } + } + catch (Exception $e) { + } + } + break; + case "GH": + //Check GalleryModules.com + if ($file == null) { + try { + $this_gm_repo = str_replace(".","",substr_replace(gallery::VERSION,"",strpos(gallery::VERSION," "))); + if($this_gm_repo == "30"){ + $file = fopen ("http://www.gallerymodules.com/m/".$module_name, "r"); + } else { + $file = fopen ("http://www.gallerymodules.com/".$this_gm_repo."m/".$module_name, "r"); + } + if ($file != null) { + $server = '(GH)'; + } + } + catch (Exception $e) { + } + } + break; } - - //Check the Gallery3 Community Contributions GitHub - if ($file == null) { - try { - $file = fopen ("http://github.com/gallery/gallery3-contrib/raw/master/3.0/modules/".$module_name."/module.info", "r"); - if ($file != null) { - $server = '(G3CC)'; - } - } - catch (Exception $e) { - //echo 'Message: ' .$e->getMessage() . '
    '; - } - } - - if ($file != null) { + + if ($file != null) { while (!feof ($file)) { $line = fgets ($file, 1024); - - //Regular expression to find & gather the version number in the remote module.info file - if (preg_match ("@version = (.*)@i", $line, $out)) { - $version = $out[1]; - break; - } + if ($server_location == "GH"){ + //GH stores only the version info + if($line == "Not entered" or $line == "See git") { + $line = ""; + } + $version = $line; + break; + } else { + //Regular expression to find & gather the version number in the remote module.info file + if (preg_match ("@version = (.*)@i", $line, $out)) { + $version = $out[1]; + break; + } + } } fclose ($file); } - return array ($version, $server); - } -} + return array ($version, $server); + } +} \ No newline at end of file diff --git a/3.0/modules/moduleupdates/helpers/moduleupdates_event.php b/3.0/modules/moduleupdates/helpers/moduleupdates_event.php index dd6efc9c..ebafb880 100644 --- a/3.0/modules/moduleupdates/helpers/moduleupdates_event.php +++ b/3.0/modules/moduleupdates/helpers/moduleupdates_event.php @@ -1,6 +1,6 @@ delete("ModuleUpdates"); //create the blank ModuleUpdates cache entry with an expiration of 0 days @@ -34,7 +34,7 @@ class moduleupdates_installer { } static function upgrade($version) { - module::set_version("moduleupdates", 2); + module::set_version("moduleupdates", 7); //Remove the ModuleUpdates cache entry 'JIC' Cache::instance()->delete("ModuleUpdates"); //Empty the ModuleUpdates cache entry so our new version starts from scratch @@ -48,4 +48,4 @@ class moduleupdates_installer { Cache::instance()->delete("ModuleUpdates"); module::delete("moduleupdates"); } -} +} \ No newline at end of file diff --git a/3.0/modules/moduleupdates/module.info b/3.0/modules/moduleupdates/module.info index cf43770b..bbf3516a 100755 --- a/3.0/modules/moduleupdates/module.info +++ b/3.0/modules/moduleupdates/module.info @@ -1,3 +1,3 @@ name = "Module Updates" description = "Compares your installed module version against the ones stored in the GitHub." -version = 3 +version = 7 \ No newline at end of file diff --git a/3.0/modules/moduleupdates/views/admin_moduleupdates.html.php b/3.0/modules/moduleupdates/views/admin_moduleupdates.html.php index 3fdc06a7..e55ed7af 100644 --- a/3.0/modules/moduleupdates/views/admin_moduleupdates.html.php +++ b/3.0/modules/moduleupdates/views/admin_moduleupdates.html.php @@ -2,8 +2,8 @@
    -

    - +

    +
    @@ -16,7 +16,6 @@
  • Green = Your version is newer than the GitHub
    ") ?>
  • Orange = Your file version is newer than the installed version
    ") ?>
  • Pink = Your installed version is newer than file version
    ") ?>
  • -
  • Blue = Does Not Exist/No information available
    ") ?>
  • ") ?>
  • " class="submit" />
@@ -25,24 +24,51 @@
    -
  • +
- - - - - - - - - - "> - - - - - - -
[File/Installed]") ?>
"; ?> "; ?> "; ?> "; ?>
+
+ Core Modules + + + + + + + + + + "> + + + + + + + +
Installed") ?>
"; ?> *"; } ?> "; } ?> "; ?> *"; } ?> $module_name['code_version']) { echo "".$module_name['core_version']."";} else { echo $module_name['core_version']; } ?> "; } ?>
+
+
+ Community Contributed Modules + + + + + + + + + + + "> + + + + + + + + +
Installed") ?>
"; ?> *"; } ?> "; } ?> "; ?> *"; } ?> $module_name['version'] or $module_name['core_version'] > $module_name['code_version']) { echo "".$module_name['contrib_version']."";} else { echo $module_name['contrib_version']; } ?> "; } ?> "; ?> *"; } ?> $module_name['version'] or $module_name['core_version'] > $module_name['code_version']) { echo "".$module_name['gh_version']."";} else { echo $module_name['gh_version']; } ?> "; } ?>
+
\ No newline at end of file diff --git a/3.0/modules/navcarousel/controllers/navcarousel.php b/3.0/modules/navcarousel/controllers/navcarousel.php index 7b8125a7..3b5401a7 100644 --- a/3.0/modules/navcarousel/controllers/navcarousel.php +++ b/3.0/modules/navcarousel/controllers/navcarousel.php @@ -1,7 +1,7 @@ script("jquery.jcarousel.min.js"); - $theme->css("skin.css"); $showelements = module::get_var("navcarousel", "showelements", "7"); $childcount = $theme->item->parent()->viewable()->children_count(); $itemoffset = intval(floor($showelements / 2)); @@ -64,7 +62,10 @@ class navcarousel_theme_Core { $onwinload = "});\n $(window).load(function () {\n"; } - Return "\n + return + $theme->script("jquery.jcarousel.min.js") + . $theme->css("skin.css") + . "\n + + +

Index for " . $this->escapeHTML($path) . "/

+ + + "; + + $files = $this->server->getPropertiesForPath($path,array( + '{DAV:}displayname', + '{DAV:}resourcetype', + '{DAV:}getcontenttype', + '{DAV:}getcontentlength', + '{DAV:}getlastmodified', + ),1); + + foreach($files as $k=>$file) { + + // This is the current directory, we can skip it + if (rtrim($file['href'],'/')==$path) continue; + + list(, $name) = Sabre_DAV_URLUtil::splitPath($file['href']); + + $type = null; + + if (isset($file[200]['{DAV:}resourcetype'])) { + $type = $file[200]['{DAV:}resourcetype']->getValue(); + + // resourcetype can have multiple values + if (is_array($type)) { + $type = implode(', ', $type); + } + + // Some name mapping is preferred + switch($type) { + case '{DAV:}collection' : + $type = 'Collection'; + break; + } + } + + // If no resourcetype was found, we attempt to use + // the contenttype property + if (!$type && isset($file[200]['{DAV:}getcontenttype'])) { + $type = $file[200]['{DAV:}getcontenttype']; + } + if (!$type) $type = 'Unknown'; + + $size = isset($file[200]['{DAV:}getcontentlength'])?(int)$file[200]['{DAV:}getcontentlength']:''; + $lastmodified = isset($file[200]['{DAV:}getlastmodified'])?$file[200]['{DAV:}getlastmodified']->getTime()->format(DateTime::ATOM):''; + + $fullPath = Sabre_DAV_URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path?$path . '/':'') . $name,'/')); + + $displayName = isset($file[200]['{DAV:}displayname'])?$file[200]['{DAV:}displayname']:$name; + + $name = $this->escapeHTML($name); + $displayName = $this->escapeHTML($displayName); + $type = $this->escapeHTML($type); + + $html.= " + + + + +"; + + } + + $html.= ""; + + if ($this->enablePost) { + $html.= ''; + } + + $html.= "
NameTypeSizeLast modified

{$displayName}{$type}{$size}{$lastmodified}

+

Create new folder

+ + Name:
+ + +
+

Upload file

+ + Name (optional):
+ File:
+ +
+
+
Generated by SabreDAV " . Sabre_DAV_Version::VERSION ."-". Sabre_DAV_Version::STABILITY . " (c)2007-2010 http://code.google.com/p/sabredav/
+ +"; + + return $html; + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Directory.php b/3.0/modules/webdav/vendor/Sabre/DAV/Directory.php new file mode 100755 index 00000000..ebc266e1 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Directory.php @@ -0,0 +1,90 @@ +getChildren() as $child) { + + if ($child->getName()==$name) return $child; + + } + throw new Sabre_DAV_Exception_FileNotFound('File not found: ' . $name); + + } + + /** + * Checks is a child-node exists. + * + * It is generally a good idea to try and override this. Usually it can be optimized. + * + * @param string $name + * @return bool + */ + public function childExists($name) { + + try { + + $this->getChild($name); + return true; + + } catch(Sabre_DAV_Exception_FileNotFound $e) { + + return false; + + } + + } + + /** + * Creates a new file in the directory + * + * @param string $name Name of the file + * @param resource $data Initial payload, passed as a readable stream resource. + * @throws Sabre_DAV_Exception_Forbidden + * @return void + */ + public function createFile($name, $data = null) { + + throw new Sabre_DAV_Exception_Forbidden('Permission denied to create file (filename ' . $name . ')'); + + } + + /** + * Creates a new subdirectory + * + * @param string $name + * @throws Sabre_DAV_Exception_Forbidden + * @return void + */ + public function createDirectory($name) { + + throw new Sabre_DAV_Exception_Forbidden('Permission denied to create directory'); + + } + + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Exception.php b/3.0/modules/webdav/vendor/Sabre/DAV/Exception.php new file mode 100755 index 00000000..46b710a0 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Exception.php @@ -0,0 +1,63 @@ +lock) { + $error = $errorNode->ownerDocument->createElementNS('DAV:','d:no-conflicting-lock'); + $errorNode->appendChild($error); + if (!is_object($this->lock)) var_dump($this->lock); + $error->appendChild($errorNode->ownerDocument->createElementNS('DAV:','d:href',$this->lock->uri)); + } + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Exception/FileNotFound.php b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/FileNotFound.php new file mode 100755 index 00000000..cd03d4c7 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/FileNotFound.php @@ -0,0 +1,28 @@ +ownerDocument->createElementNS('DAV:','d:valid-resourcetype'); + $errorNode->appendChild($error); + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Exception/LockTokenMatchesRequestUri.php b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/LockTokenMatchesRequestUri.php new file mode 100755 index 00000000..059ee346 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/LockTokenMatchesRequestUri.php @@ -0,0 +1,39 @@ +message = 'The locktoken supplied does not match any locks on this entity'; + + } + + /** + * This method allows the exception to include additonal information into the WebDAV error response + * + * @param Sabre_DAV_Server $server + * @param DOMElement $errorNode + * @return void + */ + public function serialize(Sabre_DAV_Server $server,DOMElement $errorNode) { + + $error = $errorNode->ownerDocument->createElementNS('DAV:','d:lock-token-matches-request-uri'); + $errorNode->appendChild($error); + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Exception/Locked.php b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/Locked.php new file mode 100755 index 00000000..3f15ea74 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/Locked.php @@ -0,0 +1,67 @@ +lock = $lock; + + } + + /** + * Returns the HTTP statuscode for this exception + * + * @return int + */ + public function getHTTPCode() { + + return 423; + + } + + /** + * This method allows the exception to include additonal information into the WebDAV error response + * + * @param Sabre_DAV_Server $server + * @param DOMElement $errorNode + * @return void + */ + public function serialize(Sabre_DAV_Server $server,DOMElement $errorNode) { + + if ($this->lock) { + $error = $errorNode->ownerDocument->createElementNS('DAV:','d:lock-token-submitted'); + $errorNode->appendChild($error); + if (!is_object($this->lock)) var_dump($this->lock); + $error->appendChild($errorNode->ownerDocument->createElementNS('DAV:','d:href',$this->lock->uri)); + } + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Exception/MethodNotAllowed.php b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/MethodNotAllowed.php new file mode 100755 index 00000000..67ad9a8a --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/MethodNotAllowed.php @@ -0,0 +1,44 @@ +getAllowedMethods($server->getRequestUri()); + + return array( + 'Allow' => strtoupper(implode(', ',$methods)), + ); + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Exception/NotAuthenticated.php b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/NotAuthenticated.php new file mode 100755 index 00000000..28159853 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/NotAuthenticated.php @@ -0,0 +1,28 @@ +header = $header; + + } + + /** + * Returns the HTTP statuscode for this exception + * + * @return int + */ + public function getHTTPCode() { + + return 412; + + } + + /** + * This method allows the exception to include additonal information into the WebDAV error response + * + * @param Sabre_DAV_Server $server + * @param DOMElement $errorNode + * @return void + */ + public function serialize(Sabre_DAV_Server $server,DOMElement $errorNode) { + + if ($this->header) { + $prop = $errorNode->ownerDocument->createElement('s:header'); + $prop->nodeValue = $this->header; + $errorNode->appendChild($prop); + } + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Exception/ReportNotImplemented.php b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/ReportNotImplemented.php new file mode 100755 index 00000000..64526f42 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/ReportNotImplemented.php @@ -0,0 +1,30 @@ +ownerDocument->createElementNS('DAV:','d:supported-report'); + $errorNode->appendChild($error); + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Exception/RequestedRangeNotSatisfiable.php b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/RequestedRangeNotSatisfiable.php new file mode 100755 index 00000000..723138d8 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Exception/RequestedRangeNotSatisfiable.php @@ -0,0 +1,29 @@ +path . '/' . $name; + file_put_contents($newPath,$data); + + } + + /** + * Creates a new subdirectory + * + * @param string $name + * @return void + */ + public function createDirectory($name) { + + $newPath = $this->path . '/' . $name; + mkdir($newPath); + + } + + /** + * Returns a specific child node, referenced by its name + * + * @param string $name + * @throws Sabre_DAV_Exception_FileNotFound + * @return Sabre_DAV_INode + */ + public function getChild($name) { + + $path = $this->path . '/' . $name; + + if (!file_exists($path)) throw new Sabre_DAV_Exception_FileNotFound('File with name ' . $path . ' could not be located'); + + if (is_dir($path)) { + + return new Sabre_DAV_FS_Directory($path); + + } else { + + return new Sabre_DAV_FS_File($path); + + } + + } + + /** + * Returns an array with all the child nodes + * + * @return Sabre_DAV_INode[] + */ + public function getChildren() { + + $nodes = array(); + foreach(scandir($this->path) as $node) if($node!='.' && $node!='..') $nodes[] = $this->getChild($node); + return $nodes; + + } + + /** + * Checks if a child exists. + * + * @param string $name + * @return bool + */ + public function childExists($name) { + + $path = $this->path . '/' . $name; + return file_exists($path); + + } + + /** + * Deletes all files in this directory, and then itself + * + * @return void + */ + public function delete() { + + foreach($this->getChildren() as $child) $child->delete(); + rmdir($this->path); + + } + + /** + * Returns available diskspace information + * + * @return array + */ + public function getQuotaInfo() { + + return array( + disk_total_space($this->path)-disk_free_space($this->path), + disk_free_space($this->path) + ); + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/FS/File.php b/3.0/modules/webdav/vendor/Sabre/DAV/FS/File.php new file mode 100755 index 00000000..dc2e7f98 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/FS/File.php @@ -0,0 +1,89 @@ +path,$data); + + } + + /** + * Returns the data + * + * @return string + */ + public function get() { + + return fopen($this->path,'r'); + + } + + /** + * Delete the current file + * + * @return void + */ + public function delete() { + + unlink($this->path); + + } + + /** + * Returns the size of the node, in bytes + * + * @return int + */ + public function getSize() { + + return filesize($this->path); + + } + + /** + * Returns the ETag for a file + * + * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change. + * The ETag is an arbritrary string, but MUST be surrounded by double-quotes. + * + * Return null if the ETag can not effectively be determined + * + * @return mixed + */ + public function getETag() { + + return null; + + } + + /** + * Returns the mime-type for a file + * + * If null is returned, we'll assume application/octet-stream + * + * @return mixed + */ + public function getContentType() { + + return null; + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/FS/Node.php b/3.0/modules/webdav/vendor/Sabre/DAV/FS/Node.php new file mode 100755 index 00000000..172af852 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/FS/Node.php @@ -0,0 +1,81 @@ +path = $path; + + } + + + + /** + * Returns the name of the node + * + * @return string + */ + public function getName() { + + list(, $name) = Sabre_DAV_URLUtil::splitPath($this->path); + return $name; + + } + + /** + * Renames the node + * + * @param string $name The new name + * @return void + */ + public function setName($name) { + + list($parentPath, ) = Sabre_DAV_URLUtil::splitPath($this->path); + list(, $newName) = Sabre_DAV_URLUtil::splitPath($name); + + $newPath = $parentPath . '/' . $newName; + rename($this->path,$newPath); + + $this->path = $newPath; + + } + + + + /** + * Returns the last modification time, as a unix timestamp + * + * @return int + */ + public function getLastModified() { + + return filemtime($this->path); + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/FSExt/Directory.php b/3.0/modules/webdav/vendor/Sabre/DAV/FSExt/Directory.php new file mode 100755 index 00000000..b42a9a9d --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/FSExt/Directory.php @@ -0,0 +1,135 @@ +path . '/' . $name; + file_put_contents($newPath,$data); + + } + + /** + * Creates a new subdirectory + * + * @param string $name + * @return void + */ + public function createDirectory($name) { + + // We're not allowing dots + if ($name=='.' || $name=='..') throw new Sabre_DAV_Exception_Forbidden('Permission denied to . and ..'); + $newPath = $this->path . '/' . $name; + mkdir($newPath); + + } + + /** + * Returns a specific child node, referenced by its name + * + * @param string $name + * @throws Sabre_DAV_Exception_FileNotFound + * @return Sabre_DAV_INode + */ + public function getChild($name) { + + $path = $this->path . '/' . $name; + + if (!file_exists($path)) throw new Sabre_DAV_Exception_FileNotFound('File could not be located'); + if ($name=='.' || $name=='..') throw new Sabre_DAV_Exception_Forbidden('Permission denied to . and ..'); + + if (is_dir($path)) { + + return new Sabre_DAV_FSExt_Directory($path); + + } else { + + return new Sabre_DAV_FSExt_File($path); + + } + + } + + /** + * Checks if a child exists. + * + * @param string $name + * @return bool + */ + public function childExists($name) { + + if ($name=='.' || $name=='..') + throw new Sabre_DAV_Exception_Forbidden('Permission denied to . and ..'); + + $path = $this->path . '/' . $name; + return file_exists($path); + + } + + /** + * Returns an array with all the child nodes + * + * @return Sabre_DAV_INode[] + */ + public function getChildren() { + + $nodes = array(); + foreach(scandir($this->path) as $node) if($node!='.' && $node!='..' && $node!='.sabredav') $nodes[] = $this->getChild($node); + return $nodes; + + } + + /** + * Deletes all files in this directory, and then itself + * + * @return void + */ + public function delete() { + + // Deleting all children + foreach($this->getChildren() as $child) $child->delete(); + + // Removing resource info, if its still around + if (file_exists($this->path . '/.sabredav')) unlink($this->path . '/.sabredav'); + + // Removing the directory itself + rmdir($this->path); + + return parent::delete(); + + } + + /** + * Returns available diskspace information + * + * @return array + */ + public function getQuotaInfo() { + + return array( + disk_total_space($this->path)-disk_free_space($this->path), + disk_free_space($this->path) + ); + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/FSExt/File.php b/3.0/modules/webdav/vendor/Sabre/DAV/FSExt/File.php new file mode 100755 index 00000000..987bca33 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/FSExt/File.php @@ -0,0 +1,88 @@ +path,$data); + + } + + /** + * Returns the data + * + * @return string + */ + public function get() { + + return fopen($this->path,'r'); + + } + + /** + * Delete the current file + * + * @return void + */ + public function delete() { + + unlink($this->path); + return parent::delete(); + + } + + /** + * Returns the ETag for a file + * + * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change. + * The ETag is an arbritrary string, but MUST be surrounded by double-quotes. + * + * Return null if the ETag can not effectively be determined + */ + public function getETag() { + + return '"' . md5_file($this->path). '"'; + + } + + /** + * Returns the mime-type for a file + * + * If null is returned, we'll assume application/octet-stream + */ + public function getContentType() { + + return null; + + } + + /** + * Returns the size of the file, in bytes + * + * @return int + */ + public function getSize() { + + return filesize($this->path); + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/FSExt/Node.php b/3.0/modules/webdav/vendor/Sabre/DAV/FSExt/Node.php new file mode 100755 index 00000000..0af346d1 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/FSExt/Node.php @@ -0,0 +1,276 @@ +getResourceData(); + $locks = $resourceData['locks']; + foreach($locks as $k=>$lock) { + if (time() > $lock->timeout + $lock->created) unset($locks[$k]); + } + return $locks; + + } + + /** + * Locks this node + * + * @param Sabre_DAV_Locks_LockInfo $lockInfo + * @return void + */ + function lock(Sabre_DAV_Locks_LockInfo $lockInfo) { + + // We're making the lock timeout 30 minutes + $lockInfo->timeout = 1800; + $lockInfo->created = time(); + + $resourceData = $this->getResourceData(); + if (!isset($resourceData['locks'])) $resourceData['locks'] = array(); + $current = null; + foreach($resourceData['locks'] as $k=>$lock) { + if ($lock->token === $lockInfo->token) $current = $k; + } + if (!is_null($current)) $resourceData['locks'][$current] = $lockInfo; + else $resourceData['locks'][] = $lockInfo; + + $this->putResourceData($resourceData); + + } + + /** + * Removes a lock from this node + * + * @param Sabre_DAV_Locks_LockInfo $lockInfo + * @return bool + */ + function unlock(Sabre_DAV_Locks_LockInfo $lockInfo) { + + //throw new Sabre_DAV_Exception('bla'); + $resourceData = $this->getResourceData(); + foreach($resourceData['locks'] as $k=>$lock) { + + if ($lock->token === $lockInfo->token) { + + unset($resourceData['locks'][$k]); + $this->putResourceData($resourceData); + return true; + + } + } + return false; + + } + + /** + * Updates properties on this node, + * + * @param array $mutations + * @see Sabre_DAV_IProperties::updateProperties + * @return bool|array + */ + public function updateProperties($properties) { + + $resourceData = $this->getResourceData(); + + $result = array(); + + foreach($properties as $propertyName=>$propertyValue) { + + // If it was null, we need to delete the property + if (is_null($propertyValue)) { + if (isset($resourceData['properties'][$propertyName])) { + unset($resourceData['properties'][$propertyName]); + } + } else { + $resourceData['properties'][$propertyName] = $propertyValue; + } + + } + + $this->putResourceData($resourceData); + return true; + } + + /** + * Returns a list of properties for this nodes.; + * + * The properties list is a list of propertynames the client requested, encoded as xmlnamespace#tagName, for example: http://www.example.org/namespace#author + * If the array is empty, all properties should be returned + * + * @param array $properties + * @return void + */ + function getProperties($properties) { + + $resourceData = $this->getResourceData(); + + // if the array was empty, we need to return everything + if (!$properties) return $resourceData['properties']; + + $props = array(); + foreach($properties as $property) { + if (isset($resourceData['properties'][$property])) $props[$property] = $resourceData['properties'][$property]; + } + + return $props; + + } + + /** + * Returns the path to the resource file + * + * @return string + */ + protected function getResourceInfoPath() { + + list($parentDir) = Sabre_DAV_URLUtil::splitPath($this->path); + return $parentDir . '/.sabredav'; + + } + + /** + * Returns all the stored resource information + * + * @return array + */ + protected function getResourceData() { + + $path = $this->getResourceInfoPath(); + if (!file_exists($path)) return array('locks'=>array(), 'properties' => array()); + + // opening up the file, and creating a shared lock + $handle = fopen($path,'r'); + flock($handle,LOCK_SH); + $data = ''; + + // Reading data until the eof + while(!feof($handle)) { + $data.=fread($handle,8192); + } + + // We're all good + fclose($handle); + + // Unserializing and checking if the resource file contains data for this file + $data = unserialize($data); + if (!isset($data[$this->getName()])) { + return array('locks'=>array(), 'properties' => array()); + } + + $data = $data[$this->getName()]; + if (!isset($data['locks'])) $data['locks'] = array(); + if (!isset($data['properties'])) $data['properties'] = array(); + return $data; + + } + + /** + * Updates the resource information + * + * @param array $newData + * @return void + */ + protected function putResourceData(array $newData) { + + $path = $this->getResourceInfoPath(); + + // opening up the file, and creating a shared lock + $handle = fopen($path,'a+'); + flock($handle,LOCK_EX); + $data = ''; + + rewind($handle); + + // Reading data until the eof + while(!feof($handle)) { + $data.=fread($handle,8192); + } + + // Unserializing and checking if the resource file contains data for this file + $data = unserialize($data); + $data[$this->getName()] = $newData; + ftruncate($handle,0); + rewind($handle); + + fwrite($handle,serialize($data)); + fclose($handle); + + } + + /** + * Renames the node + * + * @param string $name The new name + * @return void + */ + public function setName($name) { + + list($parentPath, ) = Sabre_DAV_URLUtil::splitPath($this->path); + list(, $newName) = Sabre_DAV_URLUtil::splitPath($name); + $newPath = $parentPath . '/' . $newName; + + // We're deleting the existing resourcedata, and recreating it + // for the new path. + $resourceData = $this->getResourceData(); + $this->deleteResourceData(); + + rename($this->path,$newPath); + $this->path = $newPath; + $this->putResourceData($resourceData); + + + } + + public function deleteResourceData() { + + // When we're deleting this node, we also need to delete any resource information + $path = $this->getResourceInfoPath(); + if (!file_exists($path)) return true; + + // opening up the file, and creating a shared lock + $handle = fopen($path,'a+'); + flock($handle,LOCK_EX); + $data = ''; + + rewind($handle); + + // Reading data until the eof + while(!feof($handle)) { + $data.=fread($handle,8192); + } + + // Unserializing and checking if the resource file contains data for this file + $data = unserialize($data); + if (isset($data[$this->getName()])) unset($data[$this->getName()]); + ftruncate($handle,0); + rewind($handle); + fwrite($handle,serialize($data)); + fclose($handle); + + } + + public function delete() { + + return $this->deleteResourceData(); + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/File.php b/3.0/modules/webdav/vendor/Sabre/DAV/File.php new file mode 100755 index 00000000..aaaf88e6 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/File.php @@ -0,0 +1,81 @@ + array( + * '{DAV:}displayname' => null, + * ), + * 424 => array( + * '{DAV:}owner' => null, + * ) + * ) + * + * In this example it was forbidden to update {DAV:}displayname. + * (403 Forbidden), which in turn also caused {DAV:}owner to fail + * (424 Failed Dependency) because the request needs to be atomic. + * + * @param array $mutations + * @return bool|array + */ + function updateProperties($properties); + + /** + * Returns a list of properties for this nodes. + * + * The properties list is a list of propertynames the client requested, + * encoded in clark-notation {xmlnamespace}tagname + * + * If the array is empty, it means 'all properties' were requested. + * + * @param array $properties + * @return void + */ + function getProperties($properties); + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/IQuota.php b/3.0/modules/webdav/vendor/Sabre/DAV/IQuota.php new file mode 100755 index 00000000..afba5efd --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/IQuota.php @@ -0,0 +1,27 @@ +dataDir = $dataDir; + + } + + protected function getFileNameForUri($uri) { + + return $this->dataDir . '/sabredav_' . md5($uri) . '.locks'; + + } + + + /** + * Returns a list of Sabre_DAV_Locks_LockInfo objects + * + * This method should return all the locks for a particular uri, including + * locks that might be set on a parent uri. + * + * @param string $uri + * @return array + */ + public function getLocks($uri) { + + $lockList = array(); + $currentPath = ''; + + foreach(explode('/',$uri) as $uriPart) { + + // weird algorithm that can probably be improved, but we're traversing the path top down + if ($currentPath) $currentPath.='/'; + $currentPath.=$uriPart; + + $uriLocks = $this->getData($currentPath); + + foreach($uriLocks as $uriLock) { + + // Unless we're on the leaf of the uri-tree we should ingore locks with depth 0 + if($uri==$currentPath || $uriLock->depth!=0) { + $uriLock->uri = $currentPath; + $lockList[] = $uriLock; + } + + } + + } + + // Checking if we can remove any of these locks + foreach($lockList as $k=>$lock) { + if (time() > $lock->timeout + $lock->created) unset($lockList[$k]); + } + return $lockList; + + } + + /** + * Locks a uri + * + * @param string $uri + * @param Sabre_DAV_Locks_LockInfo $lockInfo + * @return bool + */ + public function lock($uri,Sabre_DAV_Locks_LockInfo $lockInfo) { + + // We're making the lock timeout 30 minutes + $lockInfo->timeout = 1800; + $lockInfo->created = time(); + + $locks = $this->getLocks($uri); + foreach($locks as $k=>$lock) { + if ($lock->token == $lockInfo->token) unset($locks[$k]); + } + $locks[] = $lockInfo; + $this->putData($uri,$locks); + return true; + + } + + /** + * Removes a lock from a uri + * + * @param string $uri + * @param Sabre_DAV_Locks_LockInfo $lockInfo + * @return bool + */ + public function unlock($uri,Sabre_DAV_Locks_LockInfo $lockInfo) { + + $locks = $this->getLocks($uri); + foreach($locks as $k=>$lock) { + + if ($lock->token == $lockInfo->token) { + + unset($locks[$k]); + $this->putData($uri,$locks); + return true; + + } + } + return false; + + } + + /** + * Returns the stored data for a uri + * + * @param string $uri + * @return array + */ + protected function getData($uri) { + + $path = $this->getFilenameForUri($uri); + if (!file_exists($path)) return array(); + + // opening up the file, and creating a shared lock + $handle = fopen($path,'r'); + flock($handle,LOCK_SH); + $data = ''; + + // Reading data until the eof + while(!feof($handle)) { + $data.=fread($handle,8192); + } + + // We're all good + fclose($handle); + + // Unserializing and checking if the resource file contains data for this file + $data = unserialize($data); + if (!$data) return array(); + return $data; + + } + + /** + * Updates the lock information + * + * @param string $uri + * @param array $newData + * @return void + */ + protected function putData($uri,array $newData) { + + $path = $this->getFileNameForUri($uri); + + // opening up the file, and creating a shared lock + $handle = fopen($path,'a+'); + flock($handle,LOCK_EX); + ftruncate($handle,0); + rewind($handle); + + fwrite($handle,serialize($newData)); + fclose($handle); + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Locks/Backend/PDO.php b/3.0/modules/webdav/vendor/Sabre/DAV/Locks/Backend/PDO.php new file mode 100755 index 00000000..11c7fa96 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Locks/Backend/PDO.php @@ -0,0 +1,141 @@ +pdo = $pdo; + + } + + /** + * Returns a list of Sabre_DAV_Locks_LockInfo objects + * + * This method should return all the locks for a particular uri, including + * locks that might be set on a parent uri. + * + * @param string $uri + * @return array + */ + public function getLocks($uri) { + + // NOTE: the following 10 lines or so could be easily replaced by + // pure sql. MySQL's non-standard string concatination prevents us + // from doing this though. + $query = 'SELECT owner, token, timeout, created, scope, depth, uri FROM locks WHERE ((created + timeout) > CAST(? AS UNSIGNED INTEGER)) AND ((uri = ?)'; + $params = array(time(),$uri); + + // We need to check locks for every part in the uri. + $uriParts = explode('/',$uri); + + // We already covered the last part of the uri + array_pop($uriParts); + + $currentPath=''; + + foreach($uriParts as $part) { + + if ($currentPath) $currentPath.='/'; + $currentPath.=$part; + + $query.=' OR (depth!=0 AND uri = ?)'; + $params[] = $currentPath; + + } + + $query.=')'; + + $stmt = $this->pdo->prepare($query); + $stmt->execute($params); + $result = $stmt->fetchAll(); + + $lockList = array(); + foreach($result as $row) { + + $lockInfo = new Sabre_DAV_Locks_LockInfo(); + $lockInfo->owner = $row['owner']; + $lockInfo->token = $row['token']; + $lockInfo->timeout = $row['timeout']; + $lockInfo->created = $row['created']; + $lockInfo->scope = $row['scope']; + $lockInfo->depth = $row['depth']; + $lockInfo->uri = $row['uri']; + $lockList[] = $lockInfo; + + } + + return $lockList; + + } + + /** + * Locks a uri + * + * @param string $uri + * @param Sabre_DAV_Locks_LockInfo $lockInfo + * @return bool + */ + public function lock($uri,Sabre_DAV_Locks_LockInfo $lockInfo) { + + // We're making the lock timeout 30 minutes + $lockInfo->timeout = 30*60; + $lockInfo->created = time(); + $lockInfo->uri = $uri; + + $locks = $this->getLocks($uri); + $exists = false; + foreach($locks as $k=>$lock) { + if ($lock->token == $lockInfo->token) $exists = true; + } + + if ($exists) { + $stmt = $this->pdo->prepare('UPDATE locks SET owner = ?, timeout = ?, scope = ?, depth = ?, uri = ?, created = ? WHERE token = ?'); + $stmt->execute(array($lockInfo->owner,$lockInfo->timeout,$lockInfo->scope,$lockInfo->depth,$uri,$lockInfo->created,$lockInfo->token)); + } else { + $stmt = $this->pdo->prepare('INSERT INTO locks (owner,timeout,scope,depth,uri,created,token) VALUES (?,?,?,?,?,?,?)'); + $stmt->execute(array($lockInfo->owner,$lockInfo->timeout,$lockInfo->scope,$lockInfo->depth,$uri,$lockInfo->created,$lockInfo->token)); + } + + return true; + + } + + + + /** + * Removes a lock from a uri + * + * @param string $uri + * @param Sabre_DAV_Locks_LockInfo $lockInfo + * @return bool + */ + public function unlock($uri,Sabre_DAV_Locks_LockInfo $lockInfo) { + + $stmt = $this->pdo->prepare('DELETE FROM locks WHERE uri = ? AND token = ?'); + $stmt->execute(array($uri,$lockInfo->token)); + + return $stmt->rowCount()===1; + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Locks/LockInfo.php b/3.0/modules/webdav/vendor/Sabre/DAV/Locks/LockInfo.php new file mode 100755 index 00000000..aa174384 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Locks/LockInfo.php @@ -0,0 +1,81 @@ +addPlugin($lockPlugin); + * + * @package Sabre + * @subpackage DAV + * @copyright Copyright (C) 2007-2010 Rooftop Solutions. All rights reserved. + * @author Evert Pot (http://www.rooftopsolutions.nl/) + * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License + */ +class Sabre_DAV_Locks_Plugin extends Sabre_DAV_ServerPlugin { + + /** + * locksBackend + * + * @var Sabre_DAV_Locks_Backend_Abstract + */ + private $locksBackend; + + /** + * server + * + * @var Sabre_DAV_Server + */ + private $server; + + /** + * __construct + * + * @param Sabre_DAV_Locks_Backend_Abstract $locksBackend + * @return void + */ + public function __construct(Sabre_DAV_Locks_Backend_Abstract $locksBackend = null) { + + $this->locksBackend = $locksBackend; + + } + + /** + * Initializes the plugin + * + * This method is automatically called by the Server class after addPlugin. + * + * @param Sabre_DAV_Server $server + * @return void + */ + public function initialize(Sabre_DAV_Server $server) { + + $this->server = $server; + $server->subscribeEvent('unknownMethod',array($this,'unknownMethod')); + $server->subscribeEvent('beforeMethod',array($this,'beforeMethod'),50); + $server->subscribeEvent('afterGetProperties',array($this,'afterGetProperties')); + + } + + /** + * This method is called by the Server if the user used an HTTP method + * the server didn't recognize. + * + * This plugin intercepts the LOCK and UNLOCK methods. + * + * @param string $method + * @return bool + */ + public function unknownMethod($method, $uri) { + + switch($method) { + + case 'LOCK' : $this->httpLock($uri); return false; + case 'UNLOCK' : $this->httpUnlock($uri); return false; + + } + + } + + /** + * This method is called after most properties have been found + * it allows us to add in any Lock-related properties + * + * @param string $path + * @param array $properties + * @return bool + */ + public function afterGetProperties($path,&$newProperties) { + + foreach($newProperties[404] as $propName=>$discard) { + + $node = null; + + switch($propName) { + + case '{DAV:}supportedlock' : + $val = false; + if ($this->locksBackend) $val = true; + else { + if (!$node) $node = $this->server->tree->getNodeForPath($path); + if ($node instanceof Sabre_DAV_ILockable) $val = true; + } + $newProperties[200][$propName] = new Sabre_DAV_Property_SupportedLock($val); + unset($newProperties[404][$propName]); + break; + + case '{DAV:}lockdiscovery' : + $newProperties[200][$propName] = new Sabre_DAV_Property_LockDiscovery($this->getLocks($path)); + unset($newProperties[404][$propName]); + break; + + } + + + } + return true; + + } + + + /** + * This method is called before the logic for any HTTP method is + * handled. + * + * This plugin uses that feature to intercept access to locked resources. + * + * @param string $method + * @param string $uri + * @return bool + */ + public function beforeMethod($method, $uri) { + + switch($method) { + + case 'DELETE' : + case 'MKCOL' : + case 'PROPPATCH' : + case 'PUT' : + $lastLock = null; + if (!$this->validateLock($uri,$lastLock)) + throw new Sabre_DAV_Exception_Locked($lastLock); + break; + case 'MOVE' : + $lastLock = null; + if (!$this->validateLock(array( + $uri, + $this->server->calculateUri($this->server->httpRequest->getHeader('Destination')), + ),$lastLock)) + throw new Sabre_DAV_Exception_Locked($lastLock); + break; + case 'COPY' : + $lastLock = null; + if (!$this->validateLock( + $this->server->calculateUri($this->server->httpRequest->getHeader('Destination')), + $lastLock)) + throw new Sabre_DAV_Exception_Locked($lastLock); + break; + } + + return true; + + } + + + /** + * Use this method to tell the server this plugin defines additional + * HTTP methods. + * + * This method is passed a uri. It should only return HTTP methods that are + * available for the specified uri. + * + * @param string $uri + * @return array + */ + public function getHTTPMethods($uri) { + + if ($this->locksBackend || + $this->server->tree->getNodeForPath($uri) instanceof Sabre_DAV_ILocks) { + return array('LOCK','UNLOCK'); + } + return array(); + + } + + /** + * Returns a list of features for the HTTP OPTIONS Dav: header. + * + * In this case this is only the number 2. The 2 in the Dav: header + * indicates the server supports locks. + * + * @return array + */ + public function getFeatures() { + + return array(2); + + } + + /** + * Returns all lock information on a particular uri + * + * This function should return an array with Sabre_DAV_Locks_LockInfo objects. If there are no locks on a file, return an empty array. + * + * Additionally there is also the possibility of locks on parent nodes, so we'll need to traverse every part of the tree + * + * @param string $uri + * @return array + */ + public function getLocks($uri) { + + $lockList = array(); + $currentPath = ''; + foreach(explode('/',$uri) as $uriPart) { + + $uriLocks = array(); + if ($currentPath) $currentPath.='/'; + $currentPath.=$uriPart; + + try { + + $node = $this->server->tree->getNodeForPath($currentPath); + if ($node instanceof Sabre_DAV_ILockable) $uriLocks = $node->getLocks(); + + } catch (Sabre_DAV_Exception_FileNotFound $e){ + // In case the node didn't exist, this could be a lock-null request + } + + foreach($uriLocks as $uriLock) { + + // Unless we're on the leaf of the uri-tree we should ingore locks with depth 0 + if($uri==$currentPath || $uriLock->depth!=0) { + $uriLock->uri = $currentPath; + $lockList[] = $uriLock; + } + + } + + } + if ($this->locksBackend) $lockList = array_merge($lockList,$this->locksBackend->getLocks($uri)); + return $lockList; + + } + + /** + * Locks an uri + * + * The WebDAV lock request can be operated to either create a new lock on a file, or to refresh an existing lock + * If a new lock is created, a full XML body should be supplied, containing information about the lock such as the type + * of lock (shared or exclusive) and the owner of the lock + * + * If a lock is to be refreshed, no body should be supplied and there should be a valid If header containing the lock + * + * Additionally, a lock can be requested for a non-existant file. In these case we're obligated to create an empty file as per RFC4918:S7.3 + * + * @param string $uri + * @return void + */ + protected function httpLock($uri) { + + $lastLock = null; + if (!$this->validateLock($uri,$lastLock)) { + + // If the existing lock was an exclusive lock, we need to fail + if (!$lastLock || $lastLock->scope == Sabre_DAV_Locks_LockInfo::EXCLUSIVE) { + //var_dump($lastLock); + throw new Sabre_DAV_Exception_ConflictingLock($lastLock); + } + + } + + if ($body = $this->server->httpRequest->getBody(true)) { + // This is a new lock request + $lockInfo = $this->parseLockRequest($body); + $lockInfo->depth = $this->server->getHTTPDepth(); + $lockInfo->uri = $uri; + if($lastLock && $lockInfo->scope != Sabre_DAV_Locks_LockInfo::SHARED) throw new Sabre_DAV_Exception_ConflictingLock($lastLock); + + } elseif ($lastLock) { + + // This must have been a lock refresh + $lockInfo = $lastLock; + + // The resource could have been locked through another uri. + if ($uri!=$lockInfo->uri) $uri = $lockInfo->uri; + + } else { + + // There was neither a lock refresh nor a new lock request + throw new Sabre_DAV_Exception_BadRequest('An xml body is required for lock requests'); + + } + + if ($timeout = $this->getTimeoutHeader()) $lockInfo->timeout = $timeout; + + $newFile = false; + + // If we got this far.. we should go check if this node actually exists. If this is not the case, we need to create it first + try { + $node = $this->server->tree->getNodeForPath($uri); + + // We need to call the beforeWriteContent event for RFC3744 + $this->server->broadcastEvent('beforeWriteContent',array($uri)); + + } catch (Sabre_DAV_Exception_FileNotFound $e) { + + // It didn't, lets create it + $this->server->createFile($uri,fopen('php://memory','r')); + $newFile = true; + + } + + $this->lockNode($uri,$lockInfo); + + $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + $this->server->httpResponse->setHeader('Lock-Token','token . '>'); + $this->server->httpResponse->sendStatus($newFile?201:200); + $this->server->httpResponse->sendBody($this->generateLockResponse($lockInfo)); + + } + + /** + * Unlocks a uri + * + * This WebDAV method allows you to remove a lock from a node. The client should provide a valid locktoken through the Lock-token http header + * The server should return 204 (No content) on success + * + * @param string $uri + * @return void + */ + protected function httpUnlock($uri) { + + $lockToken = $this->server->httpRequest->getHeader('Lock-Token'); + + // If the locktoken header is not supplied, we need to throw a bad request exception + if (!$lockToken) throw new Sabre_DAV_Exception_BadRequest('No lock token was supplied'); + + $locks = $this->getLocks($uri); + + // We're grabbing the node information, just to rely on the fact it will throw a 404 when the node doesn't exist + //$this->server->tree->getNodeForPath($uri); + + foreach($locks as $lock) { + + if ('token . '>' == $lockToken) { + + $this->unlockNode($uri,$lock); + $this->server->httpResponse->setHeader('Content-Length','0'); + $this->server->httpResponse->sendStatus(204); + return; + + } + + } + + // If we got here, it means the locktoken was invalid + throw new Sabre_DAV_Exception_LockTokenMatchesRequestUri(); + + } + + /** + * Locks a uri + * + * All the locking information is supplied in the lockInfo object. The object has a suggested timeout, but this can be safely ignored + * It is important that if the existing timeout is ignored, the property is overwritten, as this needs to be sent back to the client + * + * @param string $uri + * @param Sabre_DAV_Locks_LockInfo $lockInfo + * @return void + */ + public function lockNode($uri,Sabre_DAV_Locks_LockInfo $lockInfo) { + + if (!$this->server->broadcastEvent('beforeLock',array($uri,$lockInfo))) return; + + try { + $node = $this->server->tree->getNodeForPath($uri); + if ($node instanceof Sabre_DAV_ILockable) return $node->lock($lockInfo); + } catch (Sabre_DAV_Exception_FileNotFound $e) { + // In case the node didn't exist, this could be a lock-null request + } + if ($this->locksBackend) return $this->locksBackend->lock($uri,$lockInfo); + throw new Sabre_DAV_Exception_MethodNotAllowed('Locking support is not enabled for this resource. No Locking backend was found so if you didn\'t expect this error, please check your configuration.'); + + } + + /** + * Unlocks a uri + * + * This method removes a lock from a uri. It is assumed all the supplied information is correct and verified + * + * @param string $uri + * @param Sabre_DAV_Locks_LockInfo $lockInfo + * @return void + */ + public function unlockNode($uri,Sabre_DAV_Locks_LockInfo $lockInfo) { + + if (!$this->server->broadcastEvent('beforeUnlock',array($uri,$lockInfo))) return; + try { + $node = $this->server->tree->getNodeForPath($uri); + if ($node instanceof Sabre_DAV_ILockable) return $node->unlock($lockInfo); + } catch (Sabre_DAV_Exception_FileNotFound $e) { + // In case the node didn't exist, this could be a lock-null request + } + + if ($this->locksBackend) return $this->locksBackend->unlock($uri,$lockInfo); + + } + + + /** + * Returns the contents of the HTTP Timeout header. + * + * The method formats the header into an integer. + * + * @return int + */ + public function getTimeoutHeader() { + + $header = $this->server->httpRequest->getHeader('Timeout'); + + if ($header) { + + if (stripos($header,'second-')===0) $header = (int)(substr($header,7)); + else if (strtolower($header)=='infinite') $header=Sabre_DAV_Locks_LockInfo::TIMEOUT_INFINITE; + else throw new Sabre_DAV_Exception_BadRequest('Invalid HTTP timeout header'); + + } else { + + $header = 0; + + } + + return $header; + + } + + /** + * Generates the response for successfull LOCK requests + * + * @param Sabre_DAV_Locks_LockInfo $lockInfo + * @return string + */ + protected function generateLockResponse(Sabre_DAV_Locks_LockInfo $lockInfo) { + + $dom = new DOMDocument('1.0','utf-8'); + $dom->formatOutput = true; + + $prop = $dom->createElementNS('DAV:','d:prop'); + $dom->appendChild($prop); + + $lockDiscovery = $dom->createElementNS('DAV:','d:lockdiscovery'); + $prop->appendChild($lockDiscovery); + + $lockObj = new Sabre_DAV_Property_LockDiscovery(array($lockInfo),true); + $lockObj->serialize($this->server,$lockDiscovery); + + return $dom->saveXML(); + + } + + /** + * validateLock should be called when a write operation is about to happen + * It will check if the requested url is locked, and see if the correct lock tokens are passed + * + * @param mixed $urls List of relevant urls. Can be an array, a string or nothing at all for the current request uri + * @param mixed $lastLock This variable will be populated with the last checked lock object (Sabre_DAV_Locks_LockInfo) + * @return bool + */ + protected function validateLock($urls = null,&$lastLock = null) { + + if (is_null($urls)) { + $urls = array($this->server->getRequestUri()); + } elseif (is_string($urls)) { + $urls = array($urls); + } elseif (!is_array($urls)) { + throw new Sabre_DAV_Exception('The urls parameter should either be null, a string or an array'); + } + + $conditions = $this->getIfConditions(); + + // We're going to loop through the urls and make sure all lock conditions are satisfied + foreach($urls as $url) { + + $locks = $this->getLocks($url); + + // If there were no conditions, but there were locks, we fail + if (!$conditions && $locks) { + reset($locks); + $lastLock = current($locks); + return false; + } + + // If there were no locks or conditions, we go to the next url + if (!$locks && !$conditions) continue; + + foreach($conditions as $condition) { + + $conditionUri = $condition['uri']?$this->server->calculateUri($condition['uri']):''; + + // If the condition has a url, and it isn't part of the affected url at all, check the next condition + if ($conditionUri && strpos($url,$conditionUri)!==0) continue; + + // The tokens array contians arrays with 2 elements. 0=true/false for normal/not condition, 1=locktoken + // At least 1 condition has to be satisfied + foreach($condition['tokens'] as $conditionToken) { + + $etagValid = true; + $lockValid = true; + + // key 2 can contain an etag + if ($conditionToken[2]) { + + $uri = $conditionUri?$conditionUri:$this->server->getRequestUri(); + $node = $this->server->tree->getNodeForPath($uri); + $etagValid = $node->getETag()==$conditionToken[2]; + + } + + // key 1 can contain a lock token + if ($conditionToken[1]) { + + $lockValid = false; + // Match all the locks + foreach($locks as $lockIndex=>$lock) { + + $lockToken = 'opaquelocktoken:' . $lock->token; + + // Checking NOT + if (!$conditionToken[0] && $lockToken != $conditionToken[1]) { + + // Condition valid, onto the next + $lockValid = true; + break; + } + if ($conditionToken[0] && $lockToken == $conditionToken[1]) { + + $lastLock = $lock; + // Condition valid and lock matched + unset($locks[$lockIndex]); + $lockValid = true; + break; + + } + + } + + } + + // If, after checking both etags and locks they are stil valid, + // we can continue with the next condition. + if ($etagValid && $lockValid) continue 2; + } + // No conditions matched, so we fail + throw new Sabre_DAV_Exception_PreconditionFailed('The tokens provided in the if header did not match','If'); + } + + // Conditions were met, we'll also need to check if all the locks are gone + if (count($locks)) { + + reset($locks); + + // There's still locks, we fail + $lastLock = current($locks); + return false; + + } + + + } + + // We got here, this means every condition was satisfied + return true; + + } + + /** + * This method is created to extract information from the WebDAV HTTP 'If:' header + * + * The If header can be quite complex, and has a bunch of features. We're using a regex to extract all relevant information + * The function will return an array, containg structs with the following keys + * + * * uri - the uri the condition applies to. This can be an empty string for 'every relevant url' + * * tokens - The lock token. another 2 dimensional array containg 2 elements (0 = true/false.. If this is a negative condition its set to false, 1 = the actual token) + * * etag - an etag, if supplied + * + * @return void + */ + public function getIfConditions() { + + $header = $this->server->httpRequest->getHeader('If'); + if (!$header) return array(); + + $matches = array(); + + $regex = '/(?:\<(?P.*?)\>\s)?\((?PNot\s)?(?:\<(?P[^\>]*)\>)?(?:\s?)(?:\[(?P[^\]]*)\])?\)/im'; + preg_match_all($regex,$header,$matches,PREG_SET_ORDER); + + $conditions = array(); + + foreach($matches as $match) { + + $condition = array( + 'uri' => $match['uri'], + 'tokens' => array( + array($match['not']?0:1,$match['token'],isset($match['etag'])?$match['etag']:'') + ), + ); + + if (!$condition['uri'] && count($conditions)) $conditions[count($conditions)-1]['tokens'][] = array( + $match['not']?0:1, + $match['token'], + isset($match['etag'])?$match['etag']:'' + ); + else { + $conditions[] = $condition; + } + + } + + return $conditions; + + } + + /** + * Parses a webdav lock xml body, and returns a new Sabre_DAV_Locks_LockInfo object + * + * @param string $body + * @return Sabre_DAV_Locks_LockInfo + */ + protected function parseLockRequest($body) { + + $xml = simplexml_load_string($body,null,LIBXML_NOWARNING); + $xml->registerXPathNamespace('d','DAV:'); + $lockInfo = new Sabre_DAV_Locks_LockInfo(); + + $lockInfo->owner = (string)$xml->owner; + + $lockToken = '44445502'; + $id = md5(microtime() . 'somethingrandom'); + $lockToken.='-' . substr($id,0,4) . '-' . substr($id,4,4) . '-' . substr($id,8,4) . '-' . substr($id,12,12); + + $lockInfo->token = $lockToken; + $lockInfo->scope = count($xml->xpath('d:lockscope/d:exclusive'))>0?Sabre_DAV_Locks_LockInfo::EXCLUSIVE:Sabre_DAV_Locks_LockInfo::SHARED; + + return $lockInfo; + + } + + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Mount/Plugin.php b/3.0/modules/webdav/vendor/Sabre/DAV/Mount/Plugin.php new file mode 100755 index 00000000..c2dc4296 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Mount/Plugin.php @@ -0,0 +1,79 @@ +server = $server; + $this->server->subscribeEvent('beforeMethod',array($this,'beforeMethod'), 90); + + } + + /** + * 'beforeMethod' event handles. This event handles intercepts GET requests ending + * with ?mount + * + * @param string $method + * @return void + */ + public function beforeMethod($method, $uri) { + + if ($method!='GET') return; + if ($this->server->httpRequest->getQueryString()!='mount') return; + + $currentUri = $this->server->httpRequest->getAbsoluteUri(); + + // Stripping off everything after the ? + list($currentUri) = explode('?',$currentUri); + + $this->davMount($currentUri); + + // Returning false to break the event chain + return false; + + } + + /** + * Generates the davmount response + * + * @param string $uri absolute uri + * @return void + */ + public function davMount($uri) { + + $this->server->httpResponse->sendStatus(200); + $this->server->httpResponse->setHeader('Content-Type','application/davmount+xml'); + ob_start(); + echo '', "\n"; + echo "\n"; + echo " ", htmlspecialchars($uri, ENT_NOQUOTES, 'UTF-8'), "\n"; + echo ""; + $this->server->httpResponse->sendBody(ob_get_clean()); + + } + + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Node.php b/3.0/modules/webdav/vendor/Sabre/DAV/Node.php new file mode 100755 index 00000000..8943b786 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Node.php @@ -0,0 +1,55 @@ +rootNode = $rootNode; + + } + + /** + * Returns the INode object for the requested path + * + * @param string $path + * @return Sabre_DAV_INode + */ + public function getNodeForPath($path) { + + $path = trim($path,'/'); + if (isset($this->cache[$path])) return $this->cache[$path]; + + //if (!$path || $path=='.') return $this->rootNode; + $currentNode = $this->rootNode; + $i=0; + // We're splitting up the path variable into folder/subfolder components and traverse to the correct node.. + foreach(explode('/',$path) as $pathPart) { + + // If this part of the path is just a dot, it actually means we can skip it + if ($pathPart=='.' || $pathPart=='') continue; + + if (!($currentNode instanceof Sabre_DAV_ICollection)) + throw new Sabre_DAV_Exception_FileNotFound('Could not find node at path: ' . $path); + + $currentNode = $currentNode->getChild($pathPart); + + } + + $this->cache[$path] = $currentNode; + return $currentNode; + + } + + /** + * This function allows you to check if a node exists. + * + * @param string $path + * @return bool + */ + public function nodeExists($path) { + + try { + + list($parent, $base) = Sabre_DAV_URLUtil::splitPath($path); + $parentNode = $this->getNodeForPath($parent); + return $parentNode->childExists($base); + + } catch (Sabre_DAV_Exception_FileNotFound $e) { + + return false; + + } + + } + + /** + * Returns a list of childnodes for a given path. + * + * @param string $path + * @return array + */ + public function getChildren($path) { + + $node = $this->getNodeForPath($path); + $children = $node->getChildren(); + foreach($children as $child) { + + $this->cache[trim($path,'/') . '/' . $child->getName()] = $child; + + } + return $children; + + } + + /** + * This method is called with every tree update + * + * Examples of tree updates are: + * * node deletions + * * node creations + * * copy + * * move + * * renaming nodes + * + * If Tree classes implement a form of caching, this will allow + * them to make sure caches will be expired. + * + * If a path is passed, it is assumed that the entire subtree is dirty + * + * @param string $path + * @return void + */ + public function markDirty($path) { + + // We don't care enough about sub-paths + // flushing the entire cache + $path = trim($path,'/'); + foreach($this->cache as $nodePath=>$node) { + if ($nodePath == $path || strpos($nodePath,$path.'/')===0) + unset($this->cache[$nodePath]); + + } + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Property.php b/3.0/modules/webdav/vendor/Sabre/DAV/Property.php new file mode 100755 index 00000000..ae0a64c6 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Property.php @@ -0,0 +1,25 @@ +time = $time; + } elseif (is_int($time) || ctype_digit($time)) { + $this->time = new DateTime('@' . $time); + } else { + $this->time = new DateTime($time); + } + + // Setting timezone to UTC + $this->time->setTimezone(new DateTimeZone('UTC')); + + } + + /** + * serialize + * + * @param DOMElement $prop + * @return void + */ + public function serialize(Sabre_DAV_Server $server, DOMElement $prop) { + + $doc = $prop->ownerDocument; + $prop->setAttribute('xmlns:b','urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/'); + $prop->setAttribute('b:dt','dateTime.rfc1123'); + $prop->nodeValue = $this->time->format(DateTime::RFC1123); + + } + + /** + * getTime + * + * @return DateTime + */ + public function getTime() { + + return $this->time; + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Property/Href.php b/3.0/modules/webdav/vendor/Sabre/DAV/Property/Href.php new file mode 100755 index 00000000..8b9400fb --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Property/Href.php @@ -0,0 +1,91 @@ +href = $href; + $this->autoPrefix = $autoPrefix; + + } + + /** + * Returns the uri + * + * @return string + */ + public function getHref() { + + return $this->href; + + } + + /** + * Serializes this property. + * + * It will additionally prepend the href property with the server's base uri. + * + * @param Sabre_DAV_Server $server + * @param DOMElement $dom + * @return void + */ + public function serialize(Sabre_DAV_Server $server,DOMElement $dom) { + + $prefix = $server->xmlNamespaces['DAV:']; + + $elem = $dom->ownerDocument->createElement($prefix . ':href'); + $elem->nodeValue = ($this->autoPrefix?$server->getBaseUri():'') . $this->href; + $dom->appendChild($elem); + + } + + /** + * Unserializes this property from a DOM Element + * + * This method returns an instance of this class. + * It will only decode {DAV:}href values. For non-compatible elements null will be returned. + * + * @param DOMElement $dom + * @return Sabre_DAV_Property_Href + */ + static function unserialize(DOMElement $dom) { + + if (Sabre_DAV_XMLUtil::toClarkNotation($dom->firstChild)==='{DAV:}href') { + return new self($dom->firstChild->textContent,false); + } + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Property/IHref.php b/3.0/modules/webdav/vendor/Sabre/DAV/Property/IHref.php new file mode 100755 index 00000000..56503acd --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Property/IHref.php @@ -0,0 +1,25 @@ +locks = $locks; + $this->revealLockToken = $revealLockToken; + + } + + /** + * serialize + * + * @param DOMElement $prop + * @return void + */ + public function serialize(Sabre_DAV_Server $server,DOMElement $prop) { + + $doc = $prop->ownerDocument; + + foreach($this->locks as $lock) { + + $activeLock = $doc->createElementNS('DAV:','d:activelock'); + $prop->appendChild($activeLock); + + $lockScope = $doc->createElementNS('DAV:','d:lockscope'); + $activeLock->appendChild($lockScope); + + $lockScope->appendChild($doc->createElementNS('DAV:','d:' . ($lock->scope==Sabre_DAV_Locks_LockInfo::EXCLUSIVE?'exclusive':'shared'))); + + $lockType = $doc->createElementNS('DAV:','d:locktype'); + $activeLock->appendChild($lockType); + + $lockType->appendChild($doc->createElementNS('DAV:','d:write')); + + $activeLock->appendChild($doc->createElementNS('DAV:','d:depth',($lock->depth == Sabre_DAV_Server::DEPTH_INFINITY?'infinity':$lock->depth))); + $activeLock->appendChild($doc->createElementNS('DAV:','d:timeout','Second-' . $lock->timeout)); + + if ($this->revealLockToken) { + $lockToken = $doc->createElementNS('DAV:','d:locktoken'); + $activeLock->appendChild($lockToken); + $lockToken->appendChild($doc->createElementNS('DAV:','d:href','opaquelocktoken:' . $lock->token)); + } + + $activeLock->appendChild($doc->createElementNS('DAV:','d:owner',$lock->owner)); + + } + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Property/Principal.php b/3.0/modules/webdav/vendor/Sabre/DAV/Property/Principal.php new file mode 100755 index 00000000..df3f7848 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Property/Principal.php @@ -0,0 +1,126 @@ +type = $type; + + if ($type===self::HREF && is_null($href)) { + throw new Sabre_DAV_Exception('The href argument must be specified for the HREF principal type.'); + } + $this->href = $href; + + } + + /** + * Returns the principal type + * + * @return int + */ + public function getType() { + + return $this->type; + + } + + /** + * Returns the principal uri. + * + * @return string + */ + public function getHref() { + + return $this->href; + + } + + /** + * Serializes the property into a DOMElement. + * + * @param Sabre_DAV_Server $server + * @param DOMElement $node + * @return void + */ + public function serialize(Sabre_DAV_Server $server, DOMElement $node) { + + $prefix = $server->xmlNamespaces['DAV:']; + switch($this->type) { + + case self::UNAUTHENTICATED : + $node->appendChild( + $node->ownerDocument->createElement($prefix . ':unauthenticated') + ); + break; + case self::AUTHENTICATED : + $node->appendChild( + $node->ownerDocument->createElement($prefix . ':authenticated') + ); + break; + case self::HREF : + $href = $node->ownerDocument->createElement($prefix . ':href'); + $href->nodeValue = $server->getBaseUri() . $this->href; + $node->appendChild($href); + break; + + } + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Property/ResourceType.php b/3.0/modules/webdav/vendor/Sabre/DAV/Property/ResourceType.php new file mode 100755 index 00000000..51022a48 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Property/ResourceType.php @@ -0,0 +1,80 @@ +resourceType = null; + elseif ($resourceType === Sabre_DAV_Server::NODE_DIRECTORY) + $this->resourceType = '{DAV:}collection'; + else + $this->resourceType = $resourceType; + + } + + /** + * serialize + * + * @param DOMElement $prop + * @return void + */ + public function serialize(Sabre_DAV_Server $server,DOMElement $prop) { + + $propName = null; + $rt = $this->resourceType; + if (!is_array($rt)) $rt = array($rt); + + foreach($rt as $resourceType) { + if (preg_match('/^{([^}]*)}(.*)$/',$resourceType,$propName)) { + + if (isset($server->xmlNamespaces[$propName[1]])) { + $prop->appendChild($prop->ownerDocument->createElement($server->xmlNamespaces[$propName[1]] . ':' . $propName[2])); + } else { + $prop->appendChild($prop->ownerDocument->createElementNS($propName[1],'custom:' . $propName[2])); + } + + } + } + + } + + /** + * Returns the value in clark-notation + * + * For example '{DAV:}collection' + * + * @return string + */ + public function getValue() { + + return $this->resourceType; + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Property/Response.php b/3.0/modules/webdav/vendor/Sabre/DAV/Property/Response.php new file mode 100755 index 00000000..6c75e8df --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Property/Response.php @@ -0,0 +1,156 @@ +href = $href; + $this->responseProperties = $responseProperties; + + } + + /** + * Returns the url + * + * @return string + */ + public function getHref() { + + return $this->href; + + } + + /** + * Returns the property list + * + * @return array + */ + public function getResponseProperties() { + + return $this->responseProperties; + + } + + /** + * serialize + * + * @param Sabre_DAV_Server $server + * @param DOMElement $dom + * @return void + */ + public function serialize(Sabre_DAV_Server $server,DOMElement $dom) { + + $document = $dom->ownerDocument; + $properties = $this->responseProperties; + + $xresponse = $document->createElement('d:response'); + $dom->appendChild($xresponse); + + $uri = Sabre_DAV_URLUtil::encodePath($this->href); + + // Adding the baseurl to the beginning of the url + $uri = $server->getBaseUri() . $uri; + + $xresponse->appendChild($document->createElement('d:href',$uri)); + + // The properties variable is an array containing properties, grouped by + // HTTP status + foreach($properties as $httpStatus=>$propertyGroup) { + + // The 'href' is also in this array, and it's special cased. + // We will ignore it + if ($httpStatus=='href') continue; + + // If there are no properties in this group, we can also just carry on + if (!count($propertyGroup)) continue; + + $xpropstat = $document->createElement('d:propstat'); + $xresponse->appendChild($xpropstat); + + $xprop = $document->createElement('d:prop'); + $xpropstat->appendChild($xprop); + + $nsList = $server->xmlNamespaces; + + foreach($propertyGroup as $propertyName=>$propertyValue) { + + $propName = null; + preg_match('/^{([^}]*)}(.*)$/',$propertyName,$propName); + + // special case for empty namespaces + if ($propName[1]=='') { + + $currentProperty = $document->createElement($propName[2]); + $xprop->appendChild($currentProperty); + $currentProperty->setAttribute('xmlns',''); + + } else { + + if (!isset($nsList[$propName[1]])) { + $nsList[$propName[1]] = 'x' . count($nsList); + } + + // If the namespace was defined in the top-level xml namespaces, it means + // there was already a namespace declaration, and we don't have to worry about it. + if (isset($server->xmlNamespaces[$propName[1]])) { + $currentProperty = $document->createElement($nsList[$propName[1]] . ':' . $propName[2]); + } else { + $currentProperty = $document->createElementNS($propName[1],$nsList[$propName[1]].':' . $propName[2]); + } + $xprop->appendChild($currentProperty); + + } + + if (is_scalar($propertyValue)) { + $text = $document->createTextNode($propertyValue); + $currentProperty->appendChild($text); + } elseif ($propertyValue instanceof Sabre_DAV_Property) { + $propertyValue->serialize($server,$currentProperty); + } elseif (!is_null($propertyValue)) { + throw new Sabre_DAV_Exception('Unknown property value type: ' . gettype($propertyValue) . ' for property: ' . $propertyName); + } + + } + + $xpropstat->appendChild($document->createElement('d:status',$server->httpResponse->getStatusMessage($httpStatus))); + + } + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Property/SupportedLock.php b/3.0/modules/webdav/vendor/Sabre/DAV/Property/SupportedLock.php new file mode 100755 index 00000000..0b7ca0cf --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Property/SupportedLock.php @@ -0,0 +1,76 @@ +supportsLocks = $supportsLocks; + + } + + /** + * serialize + * + * @param DOMElement $prop + * @return void + */ + public function serialize(Sabre_DAV_Server $server,DOMElement $prop) { + + $doc = $prop->ownerDocument; + + if (!$this->supportsLocks) return null; + + $lockEntry1 = $doc->createElementNS('DAV:','d:lockentry'); + $lockEntry2 = $doc->createElementNS('DAV:','d:lockentry'); + + $prop->appendChild($lockEntry1); + $prop->appendChild($lockEntry2); + + $lockScope1 = $doc->createElementNS('DAV:','d:lockscope'); + $lockScope2 = $doc->createElementNS('DAV:','d:lockscope'); + $lockType1 = $doc->createElementNS('DAV:','d:locktype'); + $lockType2 = $doc->createElementNS('DAV:','d:locktype'); + + $lockEntry1->appendChild($lockScope1); + $lockEntry1->appendChild($lockType1); + $lockEntry2->appendChild($lockScope2); + $lockEntry2->appendChild($lockType2); + + $lockScope1->appendChild($doc->createElementNS('DAV:','d:exclusive')); + $lockScope2->appendChild($doc->createElementNS('DAV:','d:shared')); + + $lockType1->appendChild($doc->createElementNS('DAV:','d:write')); + $lockType2->appendChild($doc->createElementNS('DAV:','d:write')); + + //$frag->appendXML(''); + //$frag->appendXML(''); + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Property/SupportedReportSet.php b/3.0/modules/webdav/vendor/Sabre/DAV/Property/SupportedReportSet.php new file mode 100755 index 00000000..8676f4c0 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Property/SupportedReportSet.php @@ -0,0 +1,110 @@ +addReport($reports); + + } + + /** + * Adds a report to this property + * + * The report must be a string in clark-notation. + * Multiple reports can be specified as an array. + * + * @param mixed $report + * @return void + */ + public function addReport($report) { + + if (!is_array($report)) $report = array($report); + + foreach($report as $r) { + + if (!preg_match('/^{([^}]*)}(.*)$/',$r)) + throw new Sabre_DAV_Exception('Reportname must be in clark-notation'); + + $this->reports[] = $r; + + } + + } + + /** + * Returns the list of supported reports + * + * @return array + */ + public function getValue() { + + return $this->reports; + + } + + /** + * Serializes the node + * + * @param Sabre_DAV_Server $server + * @param DOMElement $prop + * @return void + */ + public function serialize(Sabre_DAV_Server $server,DOMElement $prop) { + + foreach($this->reports as $reportName) { + + $supportedReport = $prop->ownerDocument->createElement('d:supported-report'); + $prop->appendChild($supportedReport); + + $report = $prop->ownerDocument->createElement('d:report'); + $supportedReport->appendChild($report); + + preg_match('/^{([^}]*)}(.*)$/',$reportName,$matches); + + list(, $namespace, $element) = $matches; + + $prefix = isset($server->xmlNamespaces[$namespace])?$server->xmlNamespaces[$namespace]:null; + + if ($prefix) { + $report->appendChild($prop->ownerDocument->createElement($prefix . ':' . $element)); + } else { + $report->appendChild($prop->ownerDocument->createElementNS($namespace, 'x:' . $element)); + } + + } + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Server.php b/3.0/modules/webdav/vendor/Sabre/DAV/Server.php new file mode 100755 index 00000000..21a61256 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Server.php @@ -0,0 +1,1821 @@ + 'd', + 'http://sabredav.org/ns' => 's', + ); + + /** + * The propertymap can be used to map properties from + * requests to property classes. + * + * @var array + */ + public $propertyMap = array( + ); + + public $protectedProperties = array( + // RFC4918 + '{DAV:}getcontentlength', + '{DAV:}getetag', + '{DAV:}getlastmodified', + '{DAV:}lockdiscovery', + '{DAV:}resourcetype', + '{DAV:}supportedlock', + + // RFC4331 + '{DAV:}quota-available-bytes', + '{DAV:}quota-used-bytes', + + // RFC3744 + '{DAV:}alternate-URI-set', + '{DAV:}principal-URL', + '{DAV:}group-membership', + '{DAV:}supported-privilege-set', + '{DAV:}current-user-privilege-set', + '{DAV:}acl', + '{DAV:}acl-restrictions', + '{DAV:}inherited-acl-set', + '{DAV:}principal-collection-set', + + // RFC5397 + '{DAV:}current-user-principal', + ); + + /** + * This is a flag that allow or not showing file, line and code + * of the exception in the returned XML + * + * @var bool + */ + public $debugExceptions = false; + + + /** + * Sets up the server + * + * If a Sabre_DAV_Tree object is passed as an argument, it will + * use it as the directory tree. If a Sabre_DAV_INode is passed, it + * will create a Sabre_DAV_ObjectTree and use the node as the root. + * + * If nothing is passed, a Sabre_DAV_SimpleDirectory is created in + * a Sabre_DAV_ObjectTree. + * + * @param Sabre_DAV_Tree $tree The tree object + * @return void + */ + public function __construct($treeOrNode = null) { + + if ($treeOrNode instanceof Sabre_DAV_Tree) { + $this->tree = $treeOrNode; + } elseif ($treeOrNode instanceof Sabre_DAV_INode) { + $this->tree = new Sabre_DAV_ObjectTree($treeOrNode); + } elseif (is_null($treeOrNode)) { + $root = new Sabre_DAV_SimpleDirectory('root'); + $this->tree = new Sabre_DAV_ObjectTree($root); + } else { + throw new Sabre_DAV_Exception('Invalid argument passed to constructor. Argument must either be an instance of Sabre_DAV_Tree, Sabre_DAV_INode or null'); + } + $this->httpResponse = new Sabre_HTTP_Response(); + $this->httpRequest = new Sabre_HTTP_Request(); + + } + + /** + * Starts the DAV Server + * + * @return void + */ + public function exec() { + + try { + + $this->invokeMethod($this->httpRequest->getMethod(), $this->getRequestUri()); + + } catch (Exception $e) { + + $DOM = new DOMDocument('1.0','utf-8'); + $DOM->formatOutput = true; + + $error = $DOM->createElementNS('DAV:','d:error'); + $error->setAttribute('xmlns:s',self::NS_SABREDAV); + $DOM->appendChild($error); + + $error->appendChild($DOM->createElement('s:exception',get_class($e))); + $error->appendChild($DOM->createElement('s:message',$e->getMessage())); + if ($this->debugExceptions) { + $error->appendChild($DOM->createElement('s:file',$e->getFile())); + $error->appendChild($DOM->createElement('s:line',$e->getLine())); + $error->appendChild($DOM->createElement('s:code',$e->getCode())); + $error->appendChild($DOM->createElement('s:stacktrace',$e->getTraceAsString())); + + } + $error->appendChild($DOM->createElement('s:sabredav-version',Sabre_DAV_Version::VERSION)); + + if($e instanceof Sabre_DAV_Exception) { + + $httpCode = $e->getHTTPCode(); + $e->serialize($this,$error); + $headers = $e->getHTTPHeaders($this); + + } else { + + $httpCode = 500; + $headers = array(); + + } + $headers['Content-Type'] = 'application/xml; charset=utf-8'; + + $this->httpResponse->sendStatus($httpCode); + $this->httpResponse->setHeaders($headers); + $this->httpResponse->sendBody($DOM->saveXML()); + + } + + } + + /** + * Sets the base server uri + * + * @param string $uri + * @return void + */ + public function setBaseUri($uri) { + + // If the baseUri does not end with a slash, we must add it + if ($uri[strlen($uri)-1]!=='/') + $uri.='/'; + + $this->baseUri = $uri; + + } + + /** + * Returns the base responding uri + * + * @return string + */ + public function getBaseUri() { + + if (is_null($this->baseUri)) $this->baseUri = $this->guessBaseUri(); + return $this->baseUri; + + } + + /** + * This method attempts to detect the base uri. + * Only the PATH_INFO variable is considered. + * + * If this variable is not set, the root (/) is assumed. + * + * @return void + */ + public function guessBaseUri() { + + $pathInfo = $this->httpRequest->getRawServerValue('PATH_INFO'); + $uri = $this->httpRequest->getRawServerValue('REQUEST_URI'); + + // If PATH_INFO is not found, we just return / + if (!empty($pathInfo)) { + + // We need to make sure we ignore the QUERY_STRING part + if ($pos = strpos($uri,'?')) + $uri = substr($uri,0,$pos); + + // PATH_INFO is only set for urls, such as: /example.php/path + // in that case PATH_INFO contains '/path'. + // Note that REQUEST_URI is percent encoded, while PATH_INFO is + // not, Therefore they are only comparable if we first decode + // REQUEST_INFO as well. + $decodedUri = Sabre_DAV_URLUtil::decodePath($uri); + + // A simple sanity check: + if(substr($decodedUri,strlen($decodedUri)-strlen($pathInfo))===$pathInfo) { + $baseUri = substr($decodedUri,0,strlen($decodedUri)-strlen($pathInfo)); + return rtrim($baseUri,'/') . '/'; + } + + throw new Sabre_DAV_Exception('The REQUEST_URI ('. $uri . ') did not end with the contents of PATH_INFO (' . $pathInfo . '). This server might be misconfigured.'); + + } + + // If the url ended with .php, we're going to assume that that's the server root + if (strpos($uri,'.php')===strlen($uri)-4) { + return $uri . '/'; + } + + // The last fallback is that we're just going to assume the server root. + return '/'; + + } + + /** + * Adds a plugin to the server + * + * For more information, console the documentation of Sabre_DAV_ServerPlugin + * + * @param Sabre_DAV_ServerPlugin $plugin + * @return void + */ + public function addPlugin(Sabre_DAV_ServerPlugin $plugin) { + + $this->plugins[get_class($plugin)] = $plugin; + $plugin->initialize($this); + + } + + /** + * Returns an initialized plugin by it's classname. + * + * This function returns null if the plugin was not found. + * + * @param string $className + * @return Sabre_DAV_ServerPlugin + */ + public function getPlugin($className) { + + if (isset($this->plugins[$className])) return $this->plugins[$className]; + return null; + + } + + /** + * Subscribe to an event. + * + * When the event is triggered, we'll call all the specified callbacks. + * It is possible to control the order of the callbacks through the + * priority argument. + * + * This is for example used to make sure that the authentication plugin + * is triggered before anything else. If it's not needed to change this + * number, it is recommended to ommit. + * + * @param string $event + * @param callback $callback + * @param int $priority + * @return void + */ + public function subscribeEvent($event, $callback, $priority = 100) { + + if (!isset($this->eventSubscriptions[$event])) { + $this->eventSubscriptions[$event] = array(); + } + while(isset($this->eventSubscriptions[$event][$priority])) $priority++; + $this->eventSubscriptions[$event][$priority] = $callback; + ksort($this->eventSubscriptions[$event]); + + } + + /** + * Broadcasts an event + * + * This method will call all subscribers. If one of the subscribers returns false, the process stops. + * + * The arguments parameter will be sent to all subscribers + * + * @param string $eventName + * @param array $arguments + * @return bool + */ + public function broadcastEvent($eventName,$arguments = array()) { + + if (isset($this->eventSubscriptions[$eventName])) { + + foreach($this->eventSubscriptions[$eventName] as $subscriber) { + + $result = call_user_func_array($subscriber,$arguments); + if ($result===false) return false; + + } + + } + + return true; + + } + + /** + * Handles a http request, and execute a method based on its name + * + * @param string $method + * @param string $uri + * @return void + */ + public function invokeMethod($method, $uri) { + + $method = strtoupper($method); + + if (!$this->broadcastEvent('beforeMethod',array($method, $uri))) return; + + // Make sure this is a HTTP method we support + $internalMethods = array( + 'OPTIONS', + 'GET', + 'HEAD', + 'DELETE', + 'PROPFIND', + 'MKCOL', + 'PUT', + 'PROPPATCH', + 'COPY', + 'MOVE', + 'REPORT' + ); + + if (in_array($method,$internalMethods)) { + + call_user_func(array($this,'http' . $method), $uri); + + } else { + + if ($this->broadcastEvent('unknownMethod',array($method, $uri))) { + // Unsupported method + throw new Sabre_DAV_Exception_NotImplemented(); + } + + } + + } + + // {{{ HTTP Method implementations + + /** + * HTTP OPTIONS + * + * @param string $uri + * @return void + */ + protected function httpOptions($uri) { + + $methods = $this->getAllowedMethods($uri); + + $this->httpResponse->setHeader('Allow',strtoupper(implode(', ',$methods))); + $features = array('1','3', 'extended-mkcol'); + + foreach($this->plugins as $plugin) $features = array_merge($features,$plugin->getFeatures()); + + $this->httpResponse->setHeader('DAV',implode(', ',$features)); + $this->httpResponse->setHeader('MS-Author-Via','DAV'); + $this->httpResponse->setHeader('Accept-Ranges','bytes'); + $this->httpResponse->setHeader('X-Sabre-Version',Sabre_DAV_Version::VERSION); + $this->httpResponse->setHeader('Content-Length',0); + $this->httpResponse->sendStatus(200); + + } + + /** + * HTTP GET + * + * This method simply fetches the contents of a uri, like normal + * + * @param string $uri + * @return void + */ + protected function httpGet($uri) { + + $node = $this->tree->getNodeForPath($uri,0); + + if (!$this->checkPreconditions(true)) return false; + + if (!($node instanceof Sabre_DAV_IFile)) throw new Sabre_DAV_Exception_NotImplemented('GET is only implemented on File objects'); + $body = $node->get(); + + // Converting string into stream, if needed. + if (is_string($body)) { + $stream = fopen('php://temp','r+'); + fwrite($stream,$body); + rewind($stream); + $body = $stream; + } + + /* + * TODO: getetag, getlastmodified, getsize should also be used using + * this method + */ + $httpHeaders = $this->getHTTPHeaders($uri); + + /* ContentType needs to get a default, because many webservers will otherwise + * default to text/html, and we don't want this for security reasons. + */ + if (!isset($httpHeaders['Content-Type'])) { + $httpHeaders['Content-Type'] = 'application/octet-stream'; + } + + + if (isset($httpHeaders['Content-Length'])) { + + $nodeSize = $httpHeaders['Content-Length']; + + // Need to unset Content-Length, because we'll handle that during figuring out the range + unset($httpHeaders['Content-Length']); + + } else { + $nodeSize = null; + } + + $this->httpResponse->setHeaders($httpHeaders); + + $range = $this->getHTTPRange(); + $ifRange = $this->httpRequest->getHeader('If-Range'); + $ignoreRangeHeader = false; + + // If ifRange is set, and range is specified, we first need to check + // the precondition. + if ($nodeSize && $range && $ifRange) { + + // if IfRange is parsable as a date we'll treat it as a DateTime + // otherwise, we must treat it as an etag. + try { + $ifRangeDate = new DateTime($ifRange); + + // It's a date. We must check if the entity is modified since + // the specified date. + if (!isset($httpHeaders['Last-Modified'])) $ignoreRangeHeader = true; + else { + $modified = new DateTime($httpHeaders['Last-Modified']); + if($modified > $ifRangeDate) $ignoreRangeHeader = true; + } + + } catch (Exception $e) { + + // It's an entity. We can do a simple comparison. + if (!isset($httpHeaders['ETag'])) $ignoreRangeHeader = true; + elseif ($httpHeaders['ETag']!==$ifRange) $ignoreRangeHeader = true; + } + } + + // We're only going to support HTTP ranges if the backend provided a filesize + if (!$ignoreRangeHeader && $nodeSize && $range) { + + // Determining the exact byte offsets + if (!is_null($range[0])) { + + $start = $range[0]; + $end = $range[1]?$range[1]:$nodeSize-1; + if($start >= $nodeSize) + throw new Sabre_DAV_Exception_RequestedRangeNotSatisfiable('The start offset (' . $range[0] . ') exceeded the size of the entity (' . $nodeSize . ')'); + + if($end < $start) throw new Sabre_DAV_Exception_RequestedRangeNotSatisfiable('The end offset (' . $range[1] . ') is lower than the start offset (' . $range[0] . ')'); + if($end >= $nodeSize) $end = $nodeSize-1; + + } else { + + $start = $nodeSize-$range[1]; + $end = $nodeSize-1; + + if ($start<0) $start = 0; + + } + + // New read/write stream + $newStream = fopen('php://temp','r+'); + + stream_copy_to_stream($body, $newStream, $end-$start+1, $start); + rewind($newStream); + + $this->httpResponse->setHeader('Content-Length', $end-$start+1); + $this->httpResponse->setHeader('Content-Range','bytes ' . $start . '-' . $end . '/' . $nodeSize); + $this->httpResponse->sendStatus(206); + $this->httpResponse->sendBody($newStream); + + + } else { + + if ($nodeSize) $this->httpResponse->setHeader('Content-Length',$nodeSize); + $this->httpResponse->sendStatus(200); + $this->httpResponse->sendBody($body); + + } + + } + + /** + * HTTP HEAD + * + * This method is normally used to take a peak at a url, and only get the HTTP response headers, without the body + * This is used by clients to determine if a remote file was changed, so they can use a local cached version, instead of downloading it again + * + * @param string $uri + * @return void + */ + protected function httpHead($uri) { + + $node = $this->tree->getNodeForPath($uri); + /* This information is only collection for File objects. + * Ideally we want to throw 405 Method Not Allowed for every + * non-file, but MS Office does not like this + */ + if ($node instanceof Sabre_DAV_IFile) { + $headers = $this->getHTTPHeaders($this->getRequestUri()); + if (!isset($headers['Content-Type'])) { + $headers['Content-Type'] = 'application/octet-stream'; + } + $this->httpResponse->setHeaders($headers); + } + $this->httpResponse->sendStatus(200); + + } + + /** + * HTTP Delete + * + * The HTTP delete method, deletes a given uri + * + * @param string $uri + * @return void + */ + protected function httpDelete($uri) { + + if (!$this->broadcastEvent('beforeUnbind',array($uri))) return; + $this->tree->delete($uri); + + $this->httpResponse->sendStatus(204); + $this->httpResponse->setHeader('Content-Length','0'); + + } + + + /** + * WebDAV PROPFIND + * + * This WebDAV method requests information about an uri resource, or a list of resources + * If a client wants to receive the properties for a single resource it will add an HTTP Depth: header with a 0 value + * If the value is 1, it means that it also expects a list of sub-resources (e.g.: files in a directory) + * + * The request body contains an XML data structure that has a list of properties the client understands + * The response body is also an xml document, containing information about every uri resource and the requested properties + * + * It has to return a HTTP 207 Multi-status status code + * + * @param string $uri + * @return void + */ + protected function httpPropfind($uri) { + + // $xml = new Sabre_DAV_XMLReader(file_get_contents('php://input')); + $requestedProperties = $this->parsePropfindRequest($this->httpRequest->getBody(true)); + + $depth = $this->getHTTPDepth(1); + // The only two options for the depth of a propfind is 0 or 1 + if ($depth!=0) $depth = 1; + + $newProperties = $this->getPropertiesForPath($uri,$requestedProperties,$depth); + + // This is a multi-status response + $this->httpResponse->sendStatus(207); + $this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + $data = $this->generateMultiStatus($newProperties); + $this->httpResponse->sendBody($data); + + } + + /** + * WebDAV PROPPATCH + * + * This method is called to update properties on a Node. The request is an XML body with all the mutations. + * In this XML body it is specified which properties should be set/updated and/or deleted + * + * @param string $uri + * @return void + */ + protected function httpPropPatch($uri) { + + $newProperties = $this->parsePropPatchRequest($this->httpRequest->getBody(true)); + + $result = $this->updateProperties($uri, $newProperties); + + $this->httpResponse->sendStatus(207); + $this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + + $this->httpResponse->sendBody( + $this->generateMultiStatus(array($result)) + ); + + } + + /** + * HTTP PUT method + * + * This HTTP method updates a file, or creates a new one. + * + * If a new resource was created, a 201 Created status code should be returned. If an existing resource is updated, it's a 200 Ok + * + * @param string $uri + * @return void + */ + protected function httpPut($uri) { + + $body = $this->httpRequest->getBody(); + + // Intercepting the Finder problem + if (($expected = $this->httpRequest->getHeader('X-Expected-Entity-Length')) && $expected > 0) { + + /** + Many webservers will not cooperate well with Finder PUT requests, + because it uses 'Chunked' transfer encoding for the request body. + + The symptom of this problem is that Finder sends files to the + server, but they arrive as 0-lenght files in PHP. + + If we don't do anything, the user might think they are uploading + files successfully, but they end up empty on the server. Instead, + we throw back an error if we detect this. + + The reason Finder uses Chunked, is because it thinks the files + might change as it's being uploaded, and therefore the + Content-Length can vary. + + Instead it sends the X-Expected-Entity-Length header with the size + of the file at the very start of the request. If this header is set, + but we don't get a request body we will fail the request to + protect the end-user. + */ + + // Only reading first byte + $firstByte = fread($body,1); + if (strlen($firstByte)!==1) { + throw new Sabre_DAV_Exception_Forbidden('This server is not compatible with OS/X finder. Consider using a different WebDAV client or webserver.'); + } + + // The body needs to stay intact, so we copy everything to a + // temporary stream. + + $newBody = fopen('php://temp','r+'); + fwrite($newBody,$firstByte); + stream_copy_to_stream($body, $newBody); + rewind($newBody); + + $body = $newBody; + + } + + if ($this->tree->nodeExists($uri)) { + + $node = $this->tree->getNodeForPath($uri); + + // Checking If-None-Match and related headers. + if (!$this->checkPreconditions()) return; + + // If the node is a collection, we'll deny it + if (!($node instanceof Sabre_DAV_IFile)) throw new Sabre_DAV_Exception_Conflict('PUT is not allowed on non-files.'); + if (!$this->broadcastEvent('beforeWriteContent',array($this->getRequestUri()))) return false; + + $node->put($body); + $this->httpResponse->setHeader('Content-Length','0'); + $this->httpResponse->sendStatus(200); + + } else { + + // If we got here, the resource didn't exist yet. + $this->createFile($this->getRequestUri(),$body); + $this->httpResponse->setHeader('Content-Length','0'); + $this->httpResponse->sendStatus(201); + + } + + } + + + /** + * WebDAV MKCOL + * + * The MKCOL method is used to create a new collection (directory) on the server + * + * @param string $uri + * @return void + */ + protected function httpMkcol($uri) { + + $requestBody = $this->httpRequest->getBody(true); + + if ($requestBody) { + + $contentType = $this->httpRequest->getHeader('Content-Type'); + if (strpos($contentType,'application/xml')!==0 && strpos($contentType,'text/xml')!==0) { + + // We must throw 415 for unsupport mkcol bodies + throw new Sabre_DAV_Exception_UnsupportedMediaType('The request body for the MKCOL request must have an xml Content-Type'); + + } + + $dom = Sabre_DAV_XMLUtil::loadDOMDocument($requestBody); + if (Sabre_DAV_XMLUtil::toClarkNotation($dom->firstChild)!=='{DAV:}mkcol') { + + // We must throw 415 for unsupport mkcol bodies + throw new Sabre_DAV_Exception_UnsupportedMediaType('The request body for the MKCOL request must be a {DAV:}mkcol request construct.'); + + } + + $properties = array(); + foreach($dom->firstChild->childNodes as $childNode) { + + if (Sabre_DAV_XMLUtil::toClarkNotation($childNode)!=='{DAV:}set') continue; + $properties = array_merge($properties, Sabre_DAV_XMLUtil::parseProperties($childNode, $this->propertyMap)); + + } + if (!isset($properties['{DAV:}resourcetype'])) + throw new Sabre_DAV_Exception_BadRequest('The mkcol request must include a {DAV:}resourcetype property'); + + unset($properties['{DAV:}resourcetype']); + + $resourceType = array(); + // Need to parse out all the resourcetypes + $rtNode = $dom->firstChild->getElementsByTagNameNS('urn:DAV','resourcetype'); + $rtNode = $rtNode->item(0); + foreach($rtNode->childNodes as $childNode) {; + $resourceType[] = Sabre_DAV_XMLUtil::toClarkNotation($childNode); + } + + } else { + + $properties = array(); + $resourceType = array('{DAV:}collection'); + + } + + $result = $this->createCollection($uri, $resourceType, $properties); + + if (is_array($result)) { + $this->httpResponse->sendStatus(207); + $this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + + $this->httpResponse->sendBody( + $this->generateMultiStatus(array($result)) + ); + + } else { + $this->httpResponse->setHeader('Content-Length','0'); + $this->httpResponse->sendStatus(201); + } + + } + + /** + * WebDAV HTTP MOVE method + * + * This method moves one uri to a different uri. A lot of the actual request processing is done in getCopyMoveInfo + * + * @param string $uri + * @return void + */ + protected function httpMove($uri) { + + $moveInfo = $this->getCopyAndMoveInfo(); + if ($moveInfo['destinationExists']) { + + if (!$this->broadcastEvent('beforeUnbind',array($moveInfo['destination']))) return false; + $this->tree->delete($moveInfo['destination']); + + } + + if (!$this->broadcastEvent('beforeUnbind',array($uri))) return false; + if (!$this->broadcastEvent('beforeBind',array($moveInfo['destination']))) return false; + $this->tree->move($uri,$moveInfo['destination']); + $this->broadcastEvent('afterBind',array($moveInfo['destination'])); + + // If a resource was overwritten we should send a 204, otherwise a 201 + $this->httpResponse->setHeader('Content-Length','0'); + $this->httpResponse->sendStatus($moveInfo['destinationExists']?204:201); + + } + + /** + * WebDAV HTTP COPY method + * + * This method copies one uri to a different uri, and works much like the MOVE request + * A lot of the actual request processing is done in getCopyMoveInfo + * + * @param string $uri + * @return void + */ + protected function httpCopy($uri) { + + $copyInfo = $this->getCopyAndMoveInfo(); + if ($copyInfo['destinationExists']) { + + if (!$this->broadcastEvent('beforeUnbind',array($copyInfo['destination']))) return false; + $this->tree->delete($copyInfo['destination']); + + } + if (!$this->broadcastEvent('beforeBind',array($copyInfo['destination']))) return false; + $this->tree->copy($uri,$copyInfo['destination']); + $this->broadcastEvent('afterBind',array($copyInfo['destination'])); + + // If a resource was overwritten we should send a 204, otherwise a 201 + $this->httpResponse->setHeader('Content-Length','0'); + $this->httpResponse->sendStatus($copyInfo['destinationExists']?204:201); + + } + + + + /** + * HTTP REPORT method implementation + * + * Although the REPORT method is not part of the standard WebDAV spec (it's from rfc3253) + * It's used in a lot of extensions, so it made sense to implement it into the core. + * + * @param string $uri + * @return void + */ + protected function httpReport($uri) { + + $body = $this->httpRequest->getBody(true); + $dom = Sabre_DAV_XMLUtil::loadDOMDocument($body); + + $reportName = Sabre_DAV_XMLUtil::toClarkNotation($dom->firstChild); + + if ($this->broadcastEvent('report',array($reportName,$dom, $uri))) { + + // If broadcastEvent returned true, it means the report was not supported + throw new Sabre_DAV_Exception_ReportNotImplemented(); + + } + + } + + // }}} + // {{{ HTTP/WebDAV protocol helpers + + /** + * Returns an array with all the supported HTTP methods for a specific uri. + * + * @param string $uri + * @return array + */ + public function getAllowedMethods($uri) { + + $methods = array( + 'OPTIONS', + 'GET', + 'HEAD', + 'DELETE', + 'PROPFIND', + 'PUT', + 'PROPPATCH', + 'COPY', + 'MOVE', + 'REPORT' + ); + + // The MKCOL is only allowed on an unmapped uri + try { + $node = $this->tree->getNodeForPath($uri); + } catch (Sabre_DAV_Exception_FileNotFound $e) { + $methods[] = 'MKCOL'; + } + + // We're also checking if any of the plugins register any new methods + foreach($this->plugins as $plugin) $methods = array_merge($methods,$plugin->getHTTPMethods($uri)); + array_unique($methods); + + return $methods; + + } + + /** + * Gets the uri for the request, keeping the base uri into consideration + * + * @return string + */ + public function getRequestUri() { + + return $this->calculateUri($this->httpRequest->getUri()); + + } + + /** + * Calculates the uri for a request, making sure that the base uri is stripped out + * + * @param string $uri + * @throws Sabre_DAV_Exception_Forbidden A permission denied exception is thrown whenever there was an attempt to supply a uri outside of the base uri + * @return string + */ + public function calculateUri($uri) { + + if ($uri[0]!='/' && strpos($uri,'://')) { + + $uri = parse_url($uri,PHP_URL_PATH); + + } + + $uri = str_replace('//','/',$uri); + + if (strpos($uri,$this->getBaseUri())===0) { + + return trim(Sabre_DAV_URLUtil::decodePath(substr($uri,strlen($this->getBaseUri()))),'/'); + + // A special case, if the baseUri was accessed without a trailing + // slash, we'll accept it as well. + } elseif ($uri.'/' === $this->getBaseUri()) { + + return ''; + + } else { + + throw new Sabre_DAV_Exception_Forbidden('Requested uri (' . $uri . ') is out of base uri (' . $this->getBaseUri() . ')'); + + } + + } + + /** + * Returns the HTTP depth header + * + * This method returns the contents of the HTTP depth request header. If the depth header was 'infinity' it will return the Sabre_DAV_Server::DEPTH_INFINITY object + * It is possible to supply a default depth value, which is used when the depth header has invalid content, or is completely non-existant + * + * @param mixed $default + * @return int + */ + public function getHTTPDepth($default = self::DEPTH_INFINITY) { + + // If its not set, we'll grab the default + $depth = $this->httpRequest->getHeader('Depth'); + if (is_null($depth)) return $default; + + if ($depth == 'infinity') return self::DEPTH_INFINITY; + + // If its an unknown value. we'll grab the default + if (!ctype_digit($depth)) return $default; + + return (int)$depth; + + } + + /** + * Returns the HTTP range header + * + * This method returns null if there is no well-formed HTTP range request + * header or array($start, $end). + * + * The first number is the offset of the first byte in the range. + * The second number is the offset of the last byte in the range. + * + * If the second offset is null, it should be treated as the offset of the last byte of the entity + * If the first offset is null, the second offset should be used to retrieve the last x bytes of the entity + * + * return $mixed + */ + public function getHTTPRange() { + + $range = $this->httpRequest->getHeader('range'); + if (is_null($range)) return null; + + // Matching "Range: bytes=1234-5678: both numbers are optional + + if (!preg_match('/^bytes=([0-9]*)-([0-9]*)$/i',$range,$matches)) return null; + + if ($matches[1]==='' && $matches[2]==='') return null; + + return array( + $matches[1]!==''?$matches[1]:null, + $matches[2]!==''?$matches[2]:null, + ); + + } + + + /** + * Returns information about Copy and Move requests + * + * This function is created to help getting information about the source and the destination for the + * WebDAV MOVE and COPY HTTP request. It also validates a lot of information and throws proper exceptions + * + * The returned value is an array with the following keys: + * * destination - Destination path + * * destinationExists - Wether or not the destination is an existing url (and should therefore be overwritten) + * + * @return array + */ + public function getCopyAndMoveInfo() { + + // Collecting the relevant HTTP headers + if (!$this->httpRequest->getHeader('Destination')) throw new Sabre_DAV_Exception_BadRequest('The destination header was not supplied'); + $destination = $this->calculateUri($this->httpRequest->getHeader('Destination')); + $overwrite = $this->httpRequest->getHeader('Overwrite'); + if (!$overwrite) $overwrite = 'T'; + if (strtoupper($overwrite)=='T') $overwrite = true; + elseif (strtoupper($overwrite)=='F') $overwrite = false; + // We need to throw a bad request exception, if the header was invalid + else throw new Sabre_DAV_Exception_BadRequest('The HTTP Overwrite header should be either T or F'); + + list($destinationDir) = Sabre_DAV_URLUtil::splitPath($destination); + + try { + $destinationParent = $this->tree->getNodeForPath($destinationDir); + if (!($destinationParent instanceof Sabre_DAV_ICollection)) throw new Sabre_DAV_Exception_UnsupportedMediaType('The destination node is not a collection'); + } catch (Sabre_DAV_Exception_FileNotFound $e) { + + // If the destination parent node is not found, we throw a 409 + throw new Sabre_DAV_Exception_Conflict('The destination node is not found'); + } + + try { + + $destinationNode = $this->tree->getNodeForPath($destination); + + // If this succeeded, it means the destination already exists + // we'll need to throw precondition failed in case overwrite is false + if (!$overwrite) throw new Sabre_DAV_Exception_PreconditionFailed('The destination node already exists, and the overwrite header is set to false','Overwrite'); + + } catch (Sabre_DAV_Exception_FileNotFound $e) { + + // Destination didn't exist, we're all good + $destinationNode = false; + + + + } + + // These are the three relevant properties we need to return + return array( + 'destination' => $destination, + 'destinationExists' => $destinationNode==true, + 'destinationNode' => $destinationNode, + ); + + } + + /** + * Returns a list of properties for a path + * + * This is a simplified version getPropertiesForPath. + * if you aren't interested in status codes, but you just + * want to have a flat list of properties. Use this method. + * + * @param string $path + * @param array $propertyNames + */ + public function getProperties($path, $propertyNames) { + + $result = $this->getPropertiesForPath($path,$propertyNames,0); + return $result[0][200]; + + } + + /** + * Returns a list of HTTP headers for a particular resource + * + * The generated http headers are based on properties provided by the + * resource. The method basically provides a simple mapping between + * DAV property and HTTP header. + * + * The headers are intended to be used for HEAD and GET requests. + * + * @param string $path + */ + public function getHTTPHeaders($path) { + + $propertyMap = array( + '{DAV:}getcontenttype' => 'Content-Type', + '{DAV:}getcontentlength' => 'Content-Length', + '{DAV:}getlastmodified' => 'Last-Modified', + '{DAV:}getetag' => 'ETag', + ); + + $properties = $this->getProperties($path,array_keys($propertyMap)); + + $headers = array(); + foreach($propertyMap as $property=>$header) { + if (!isset($properties[$property])) continue; + + if (is_scalar($properties[$property])) { + $headers[$header] = $properties[$property]; + + // GetLastModified gets special cased + } elseif ($properties[$property] instanceof Sabre_DAV_Property_GetLastModified) { + $headers[$header] = $properties[$property]->getTime()->format(DateTime::RFC1123); + } + + } + + return $headers; + + } + + /** + * Returns a list of properties for a given path + * + * The path that should be supplied should have the baseUrl stripped out + * The list of properties should be supplied in Clark notation. If the list is empty + * 'allprops' is assumed. + * + * If a depth of 1 is requested child elements will also be returned. + * + * @param string $path + * @param array $propertyNames + * @param int $depth + * @return array + */ + public function getPropertiesForPath($path,$propertyNames = array(),$depth = 0) { + + if ($depth!=0) $depth = 1; + + $returnPropertyList = array(); + + $parentNode = $this->tree->getNodeForPath($path); + $nodes = array( + $path => $parentNode + ); + if ($depth==1 && $parentNode instanceof Sabre_DAV_ICollection) { + foreach($this->tree->getChildren($path) as $childNode) + $nodes[$path . '/' . $childNode->getName()] = $childNode; + } + + // If the propertyNames array is empty, it means all properties are requested. + // We shouldn't actually return everything we know though, and only return a + // sensible list. + $allProperties = count($propertyNames)==0; + + foreach($nodes as $myPath=>$node) { + + $newProperties = array( + '200' => array(), + '404' => array(), + ); + if ($node instanceof Sabre_DAV_IProperties) + $newProperties['200'] = $node->getProperties($propertyNames); + + if ($allProperties) { + + // Default list of propertyNames, when all properties were requested. + $propertyNames = array( + '{DAV:}getlastmodified', + '{DAV:}getcontentlength', + '{DAV:}resourcetype', + '{DAV:}quota-used-bytes', + '{DAV:}quota-available-bytes', + '{DAV:}getetag', + '{DAV:}getcontenttype', + ); + + // We need to make sure this includes any propertyname already returned from + // $node->getProperties(); + $propertyNames = array_merge($propertyNames, array_keys($newProperties[200])); + + // Making sure there's no double entries + $propertyNames = array_unique($propertyNames); + + } + + // If the resourceType was not part of the list, we manually add it + // and mark it for removal. We need to know the resourcetype in order + // to make certain decisions about the entry. + // WebDAV dictates we should add a / and the end of href's for collections + $removeRT = false; + if (!in_array('{DAV:}resourcetype',$propertyNames)) { + $propertyNames[] = '{DAV:}resourcetype'; + $removeRT = true; + } + + foreach($propertyNames as $prop) { + + if (isset($newProperties[200][$prop])) continue; + + switch($prop) { + case '{DAV:}getlastmodified' : if ($node->getLastModified()) $newProperties[200][$prop] = new Sabre_DAV_Property_GetLastModified($node->getLastModified()); break; + case '{DAV:}getcontentlength' : if ($node instanceof Sabre_DAV_IFile) $newProperties[200][$prop] = (int)$node->getSize(); break; + case '{DAV:}resourcetype' : $newProperties[200][$prop] = new Sabre_DAV_Property_ResourceType($node instanceof Sabre_DAV_ICollection?self::NODE_DIRECTORY:self::NODE_FILE); break; + case '{DAV:}quota-used-bytes' : + if ($node instanceof Sabre_DAV_IQuota) { + $quotaInfo = $node->getQuotaInfo(); + $newProperties[200][$prop] = $quotaInfo[0]; + } + break; + case '{DAV:}quota-available-bytes' : + if ($node instanceof Sabre_DAV_IQuota) { + $quotaInfo = $node->getQuotaInfo(); + $newProperties[200][$prop] = $quotaInfo[1]; + } + break; + case '{DAV:}getetag' : if ($node instanceof Sabre_DAV_IFile && $etag = $node->getETag()) $newProperties[200][$prop] = $etag; break; + case '{DAV:}getcontenttype' : if ($node instanceof Sabre_DAV_IFile && $ct = $node->getContentType()) $newProperties[200][$prop] = $ct; break; + case '{DAV:}supported-report-set' : $newProperties[200][$prop] = new Sabre_DAV_Property_SupportedReportSet(); break; + + } + + // If we were unable to find the property, we will list it as 404. + if (!$allProperties && !isset($newProperties[200][$prop])) $newProperties[404][$prop] = null; + + } + + $this->broadcastEvent('afterGetProperties',array(trim($myPath,'/'),&$newProperties)); + + $newProperties['href'] = trim($myPath,'/'); + + // Its is a WebDAV recommendation to add a trailing slash to collectionnames. + // Apple's iCal also requires a trailing slash for principals (rfc 3744). + // Therefore we add a trailing / for any non-file. This might need adjustments + // if we find there are other edge cases. + if ($myPath!='' && isset($newProperties[200]['{DAV:}resourcetype']) && $newProperties[200]['{DAV:}resourcetype']->getValue()!==null) $newProperties['href'] .='/'; + + // If the resourcetype property was manually added to the requested property list, + // we will remove it again. + if ($removeRT) unset($newProperties[200]['{DAV:}resourcetype']); + + $returnPropertyList[] = $newProperties; + + } + + return $returnPropertyList; + + } + + /** + * This method is invoked by sub-systems creating a new file. + * + * Currently this is done by HTTP PUT and HTTP LOCK (in the Locks_Plugin). + * It was important to get this done through a centralized function, + * allowing plugins to intercept this using the beforeCreateFile event. + * + * @param string $uri + * @param resource $data + * @return void + */ + public function createFile($uri,$data) { + + list($dir,$name) = Sabre_DAV_URLUtil::splitPath($uri); + + if (!$this->broadcastEvent('beforeBind',array($uri))) return; + if (!$this->broadcastEvent('beforeCreateFile',array($uri,$data))) return; + + $parent = $this->tree->getNodeForPath($dir); + $parent->createFile($name,$data); + $this->tree->markDirty($dir); + + $this->broadcastEvent('afterBind',array($uri)); + } + + /** + * This method is invoked by sub-systems creating a new directory. + * + * @param string $uri + * @return void + */ + public function createDirectory($uri) { + + $this->createCollection($uri,array('{DAV:}collection'),array()); + + } + + /** + * Use this method to create a new collection + * + * The {DAV:}resourcetype is specified using the resourceType array. + * At the very least it must contain {DAV:}collection. + * + * The properties array can contain a list of additional properties. + * + * @param string $uri The new uri + * @param array $resourceType The resourceType(s) + * @param array $properties A list of properties + * @return void + */ + public function createCollection($uri, array $resourceType, array $properties) { + + list($parentUri,$newName) = Sabre_DAV_URLUtil::splitPath($uri); + + // Making sure {DAV:}collection was specified as resourceType + if (!in_array('{DAV:}collection', $resourceType)) { + throw new Sabre_DAV_Exception_InvalidResourceType('The resourceType for this collection must at least include {DAV:}collection'); + } + + + // Making sure the parent exists + try { + + $parent = $this->tree->getNodeForPath($parentUri); + + } catch (Sabre_DAV_Exception_FileNotFound $e) { + + throw new Sabre_DAV_Exception_Conflict('Parent node does not exist'); + + } + + // Making sure the parent is a collection + if (!$parent instanceof Sabre_DAV_ICollection) { + throw new Sabre_DAV_Exception_Conflict('Parent node is not a collection'); + } + + + + // Making sure the child does not already exist + try { + $parent->getChild($newName); + + // If we got here.. it means there's already a node on that url, and we need to throw a 405 + throw new Sabre_DAV_Exception_MethodNotAllowed('The resource you tried to create already exists'); + + } catch (Sabre_DAV_Exception_FileNotFound $e) { + // This is correct + } + + + if (!$this->broadcastEvent('beforeBind',array($uri))) return; + + // There are 2 modes of operation. The standard collection + // creates the directory, and then updates properties + // the extended collection can create it directly. + if ($parent instanceof Sabre_DAV_IExtendedCollection) { + + $parent->createExtendedCollection($newName, $resourceType, $properties); + + } else { + + // No special resourcetypes are supported + if (count($resourceType)>1) { + throw new Sabre_DAV_Exception_InvalidResourceType('The {DAV:}resourcetype you specified is not supported here.'); + } + + $parent->createDirectory($newName); + $rollBack = false; + $exception = null; + $errorResult = null; + + if (count($properties)>0) { + + try { + + $errorResult = $this->updateProperties($uri, $properties); + if (!isset($errorResult[200])) { + $rollBack = true; + } + + } catch (Sabre_DAV_Exception $e) { + + $rollBack = true; + $exception = $e; + + } + + } + + if ($rollBack) { + if (!$this->broadcastEvent('beforeUnbind',array($uri))) return; + $this->tree->delete($uri); + + // Re-throwing exception + if ($exception) throw $exception; + + return $errorResult; + } + + } + $this->tree->markDirty($parentUri); + $this->broadcastEvent('afterBind',array($uri)); + + } + + /** + * This method updates a resource's properties + * + * The properties array must be a list of properties. Array-keys are + * property names in clarknotation, array-values are it's values. + * If a property must be deleted, the value should be null. + * + * Note that this request should either completely succeed, or + * completely fail. + * + * The response is an array with statuscodes for keys, which in turn + * contain arrays with propertynames. This response can be used + * to generate a multistatus body. + * + * @param string $uri + * @param array $properties + * @return array + */ + public function updateProperties($uri, array $properties) { + + // we'll start by grabbing the node, this will throw the appropriate + // exceptions if it doesn't. + $node = $this->tree->getNodeForPath($uri); + + $result = array( + 200 => array(), + 403 => array(), + 424 => array(), + ); + $remainingProperties = $properties; + $hasError = false; + + + // If the node is not an instance of Sabre_DAV_IProperties, every + // property is 403 Forbidden + // simply return a 405. + if (!($node instanceof Sabre_DAV_IProperties)) { + $hasError = true; + foreach($properties as $propertyName=> $value) { + $result[403][$propertyName] = null; + } + $remainingProperties = array(); + } + + // Running through all properties to make sure none of them are protected + if (!$hasError) foreach($properties as $propertyName => $value) { + if(in_array($propertyName, $this->protectedProperties)) { + $result[403][$propertyName] = null; + unset($remainingProperties[$propertyName]); + $hasError = true; + } + } + + // Only if there were no errors we may attempt to update the resource + if (!$hasError) { + $updateResult = $node->updateProperties($properties); + $remainingProperties = array(); + + if ($updateResult===true) { + // success + foreach($properties as $propertyName=>$value) { + $result[200][$propertyName] = null; + } + + } elseif ($updateResult===false) { + // The node failed to update the properties for an + // unknown reason + foreach($properties as $propertyName=>$value) { + $result[403][$propertyName] = null; + } + + } elseif (is_array($updateResult)) { + // The node has detailed update information + $result = $updateResult; + + } else { + throw new Sabre_DAV_Exception('Invalid result from updateProperties'); + } + + } + + foreach($remainingProperties as $propertyName=>$value) { + // if there are remaining properties, it must mean + // there's a dependency failure + $result[424][$propertyName] = null; + } + + // Removing empty array values + foreach($result as $status=>$props) { + + if (count($props)===0) unset($result[$status]); + + } + $result['href'] = $uri; + return $result; + + } + + /** + * This method checks the main HTTP preconditions. + * + * Currently these are: + * * If-Match + * * If-None-Match + * * If-Modified-Since + * * If-Unmodified-Since + * + * The method will return true if all preconditions are met + * The method will return false, or throw an exception if preconditions + * failed. If false is returned the operation should be aborted, and + * the appropriate HTTP response headers are already set. + * + * Normally this method will throw 412 Precondition Failed for failures + * related to If-None-Match, If-Match and If-Unmodified Since. It will + * set the status to 304 Not Modified for If-Modified_since. + * + * If the $handleAsGET argument is set to true, it will also return 304 + * Not Modified for failure of the If-None-Match precondition. This is the + * desired behaviour for HTTP GET and HTTP HEAD requests. + * + * @return bool + */ + public function checkPreconditions($handleAsGET = false) { + + $uri = $this->getRequestUri(); + $node = null; + $lastMod = null; + $etag = null; + + if ($ifMatch = $this->httpRequest->getHeader('If-Match')) { + + // If-Match contains an entity tag. Only if the entity-tag + // matches we are allowed to make the request succeed. + // If the entity-tag is '*' we are only allowed to make the + // request succeed if a resource exists at that url. + try { + $node = $this->tree->getNodeForPath($uri); + } catch (Sabre_DAV_Exception_FileNotFound $e) { + throw new Sabre_DAV_Exception_PreconditionFailed('An If-Match header was specified and the resource did not exist','If-Match'); + } + + // Only need to check entity tags if they are not * + if ($ifMatch!=='*') { + + // There can be multiple etags + $ifMatch = explode(',',$ifMatch); + $haveMatch = false; + foreach($ifMatch as $ifMatchItem) { + + // Stripping any extra spaces + $ifMatchItem = trim($ifMatchItem,' '); + + $etag = $node->getETag(); + if ($etag===$ifMatchItem) { + $haveMatch = true; + } + } + if (!$haveMatch) { + throw new Sabre_DAV_Exception_PreconditionFailed('An If-Match header was specified, but none of the specified the ETags matched.','If-Match'); + } + } + } + + if ($ifNoneMatch = $this->httpRequest->getHeader('If-None-Match')) { + + // The If-None-Match header contains an etag. + // Only if the ETag does not match the current ETag, the request will succeed + // The header can also contain *, in which case the request + // will only succeed if the entity does not exist at all. + $nodeExists = true; + if (!$node) { + try { + $node = $this->tree->getNodeForPath($uri); + } catch (Sabre_DAV_Exception_FileNotFound $e) { + $nodeExists = false; + } + } + if ($nodeExists) { + $haveMatch = false; + if ($ifNoneMatch==='*') $haveMatch = true; + else { + + // There might be multiple etags + $ifNoneMatch = explode(',', $ifNoneMatch); + $etag = $node->getETag(); + + foreach($ifNoneMatch as $ifNoneMatchItem) { + + // Stripping any extra spaces + $ifNoneMatchItem = trim($ifNoneMatchItem,' '); + + if ($etag===$ifNoneMatchItem) $haveMatch = true; + + } + + } + + if ($haveMatch) { + if ($handleAsGET) { + $this->httpResponse->sendStatus(304); + return false; + } else { + throw new Sabre_DAV_Exception_PreconditionFailed('An If-None-Match header was specified, but the ETag matched (or * was specified).','If-None-Match'); + } + } + } + + } + + if (!$ifNoneMatch && ($ifModifiedSince = $this->httpRequest->getHeader('If-Modified-Since'))) { + + // The If-Modified-Since header contains a date. We + // will only return the entity if it has been changed since + // that date. If it hasn't been changed, we return a 304 + // header + // Note that this header only has to be checked if there was no If-None-Match header + // as per the HTTP spec. + $date = Sabre_HTTP_Util::parseHTTPDate($ifModifiedSince); + + if ($date) { + if (is_null($node)) { + $node = $this->tree->getNodeForPath($uri); + } + $lastMod = $node->getLastModified(); + if ($lastMod) { + $lastMod = new DateTime('@' . $lastMod); + if ($lastMod <= $date) { + $this->httpResponse->sendStatus(304); + return false; + } + } + } + } + + if ($ifUnmodifiedSince = $this->httpRequest->getHeader('If-Unmodified-Since')) { + + // The If-Unmodified-Since will allow allow the request if the + // entity has not changed since the specified date. + $date = Sabre_HTTP_Util::parseHTTPDate($ifUnmodifiedSince); + + // We must only check the date if it's valid + if ($date) { + if (is_null($node)) { + $node = $this->tree->getNodeForPath($uri); + } + $lastMod = $node->getLastModified(); + if ($lastMod) { + $lastMod = new DateTime('@' . $lastMod); + if ($lastMod > $date) { + throw new Sabre_DAV_Exception_PreconditionFailed('An If-Unmodified-Since header was specified, but the entity has been changed since the specified date.','If-Unmodified-Since'); + } + } + } + + } + return true; + + } + + // }}} + // {{{ XML Readers & Writers + + + /** + * Generates a WebDAV propfind response body based on a list of nodes + * + * @param array $fileProperties The list with nodes + * @param array $requestedProperties The properties that should be returned + * @return string + */ + public function generateMultiStatus(array $fileProperties) { + + $dom = new DOMDocument('1.0','utf-8'); + //$dom->formatOutput = true; + $multiStatus = $dom->createElement('d:multistatus'); + $dom->appendChild($multiStatus); + + // Adding in default namespaces + foreach($this->xmlNamespaces as $namespace=>$prefix) { + + $multiStatus->setAttribute('xmlns:' . $prefix,$namespace); + + } + + foreach($fileProperties as $entry) { + + $href = $entry['href']; + unset($entry['href']); + + $response = new Sabre_DAV_Property_Response($href,$entry); + $response->serialize($this,$multiStatus); + + } + + return $dom->saveXML(); + + } + + /** + * This method parses a PropPatch request + * + * PropPatch changes the properties for a resource. This method + * returns a list of properties. + * + * The keys in the returned array contain the property name (e.g.: {DAV:}displayname, + * and the value contains the property value. If a property is to be removed the value + * will be null. + * + * @param string $body xml body + * @return array list of properties in need of updating or deletion + */ + public function parsePropPatchRequest($body) { + + //We'll need to change the DAV namespace declaration to something else in order to make it parsable + $dom = Sabre_DAV_XMLUtil::loadDOMDocument($body); + + $newProperties = array(); + + foreach($dom->firstChild->childNodes as $child) { + + if ($child->nodeType !== XML_ELEMENT_NODE) continue; + + $operation = Sabre_DAV_XMLUtil::toClarkNotation($child); + + if ($operation!=='{DAV:}set' && $operation!=='{DAV:}remove') continue; + + $innerProperties = Sabre_DAV_XMLUtil::parseProperties($child, $this->propertyMap); + + foreach($innerProperties as $propertyName=>$propertyValue) { + + if ($operation==='{DAV:}remove') { + $propertyValue = null; + } + + $newProperties[$propertyName] = $propertyValue; + + } + + } + + return $newProperties; + + } + + /** + * This method parses the PROPFIND request and returns its information + * + * This will either be a list of properties, or an empty array; in which case + * an {DAV:}allprop was requested. + * + * @param string $body + * @return array + */ + public function parsePropFindRequest($body) { + + // If the propfind body was empty, it means IE is requesting 'all' properties + if (!$body) return array(); + + $dom = Sabre_DAV_XMLUtil::loadDOMDocument($body); + $elem = $dom->getElementsByTagNameNS('urn:DAV','propfind')->item(0); + return array_keys(Sabre_DAV_XMLUtil::parseProperties($elem)); + + } + + // }}} + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/ServerPlugin.php b/3.0/modules/webdav/vendor/Sabre/DAV/ServerPlugin.php new file mode 100755 index 00000000..f38e8aa3 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/ServerPlugin.php @@ -0,0 +1,60 @@ +name = $name; + foreach($children as $child) { + + if (!($child instanceof Sabre_DAV_INode)) throw new Sabre_DAV_Exception('Only instances of Sabre_DAV_INode are allowed to be passed in the children argument'); + $this->addChild($child); + + } + + } + + /** + * Adds a new childnode to this collection + * + * @param Sabre_DAV_INode $child + * @return void + */ + public function addChild(Sabre_DAV_INode $child) { + + $this->children[$child->getName()] = $child; + + } + + /** + * Returns the name of the collection + * + * @return string + */ + public function getName() { + + return $this->name; + + } + + /** + * Returns a child object, by its name. + * + * This method makes use of the getChildren method to grab all the child nodes, and compares the name. + * Generally its wise to override this, as this can usually be optimized + * + * @param string $name + * @throws Sabre_DAV_Exception_FileNotFound + * @return Sabre_DAV_INode + */ + public function getChild($name) { + + if (isset($this->children[$name])) return $this->children[$name]; + throw new Sabre_DAV_Exception_FileNotFound('File not found: ' . $name); + + } + + /** + * Returns a list of children for this collection + * + * @return array + */ + public function getChildren() { + + return array_values($this->children); + + } + + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/TemporaryFileFilterPlugin.php b/3.0/modules/webdav/vendor/Sabre/DAV/TemporaryFileFilterPlugin.php new file mode 100755 index 00000000..1e15865e --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/TemporaryFileFilterPlugin.php @@ -0,0 +1,275 @@ +dataDir = $dataDir; + + } + + /** + * Initialize the plugin + * + * This is called automatically be the Server class after this plugin is + * added with Sabre_DAV_Server::addPlugin() + * + * @param Sabre_DAV_Server $server + * @return void + */ + public function initialize(Sabre_DAV_Server $server) { + $this->server = $server; + $server->subscribeEvent('beforeMethod',array($this,'beforeMethod')); + $server->subscribeEvent('beforeCreateFile',array($this,'beforeCreateFile')); + + } + + /** + * This method is called before any HTTP method handler + * + * This method intercepts any GET, DELETE, PUT and PROPFIND calls to + * filenames that are known to match the 'temporary file' regex. + * + * @param string $method + * @return bool + */ + public function beforeMethod($method, $uri) { + + if (!$tempLocation = $this->isTempFile($uri)) + return true; + + switch($method) { + case 'GET' : + return $this->httpGet($tempLocation); + case 'PUT' : + return $this->httpPut($tempLocation); + case 'PROPFIND' : + return $this->httpPropfind($tempLocation, $uri); + case 'DELETE' : + return $this->httpDelete($tempLocation); + } + return true; + + } + + /** + * This method is invoked if some subsystem creates a new file. + * + * This is used to deal with HTTP LOCK requests which create a new + * file. + * + * @param string $uri + * @param resource $data + * @return bool + */ + public function beforeCreateFile($uri,$data) { + if ($tempPath = $this->isTempFile($uri)) { + $hR = $this->server->httpResponse; + $hR->setHeader('X-Sabre-Temp','true'); + file_put_contents($tempPath,$data); + return false; + } + return true; + + } + + /** + * This method will check if the url matches the temporary file pattern + * if it does, it will return an path based on $this->dataDir for the + * temporary file storage. + * + * @param string $path + * @return boolean|string + */ + protected function isTempFile($path) { + + // We're only interested in the basename. + list(, $tempPath) = Sabre_DAV_URLUtil::splitPath($path); + + foreach($this->temporaryFilePatterns as $tempFile) { + + if (preg_match($tempFile,$tempPath)) { + return $this->dataDir . '/sabredav_' . md5($path) . '.tempfile'; + } + + } + + return false; + + } + + + /** + * This method handles the GET method for temporary files. + * If the file doesn't exist, it will return false which will kick in + * the regular system for the GET method. + * + * @param string $tempLocation + * @return bool + */ + public function httpGet($tempLocation) { + + if (!file_exists($tempLocation)) return true; + + $hR = $this->server->httpResponse; + $hR->setHeader('Content-Type','application/octet-stream'); + $hR->setHeader('Content-Length',filesize($tempLocation)); + $hR->setHeader('X-Sabre-Temp','true'); + $hR->sendStatus(200); + $hR->sendBody(fopen($tempLocation,'r')); + return false; + + } + + /** + * This method handles the PUT method. + * + * @param string $tempLocation + * @return bool + */ + public function httpPut($tempLocation) { + error_log("Tempfile PUT"); + $hR = $this->server->httpResponse; + $hR->setHeader('X-Sabre-Temp','true'); + + $newFile = !file_exists($tempLocation); + + if (!$newFile && ($this->server->httpRequest->getHeader('If-None-Match'))) { + throw new Sabre_DAV_Exception_PreconditionFailed('The resource already exists, and an If-None-Match header was supplied'); + } + + file_put_contents($tempLocation,$this->server->httpRequest->getBody()); + $hR->sendStatus($newFile?201:200); + return false; + + } + + /** + * This method handles the DELETE method. + * + * If the file didn't exist, it will return false, which will make the + * standard HTTP DELETE handler kick in. + * + * @param string $tempLocation + * @return bool + */ + public function httpDelete($tempLocation) { + + if (!file_exists($tempLocation)) return true; + + unlink($tempLocation); + $hR = $this->server->httpResponse; + $hR->setHeader('X-Sabre-Temp','true'); + $hR->sendStatus(204); + return false; + + } + + /** + * This method handles the PROPFIND method. + * + * It's a very lazy method, it won't bother checking the request body + * for which properties were requested, and just sends back a default + * set of properties. + * + * @param string $tempLocation + * @return void + */ + public function httpPropfind($tempLocation, $uri) { + + if (!file_exists($tempLocation)) return true; + + $hR = $this->server->httpResponse; + $hR->setHeader('X-Sabre-Temp','true'); + $hR->sendStatus(207); + $hR->setHeader('Content-Type','application/xml; charset=utf-8'); + + $requestedProps = $this->server->parsePropFindRequest($this->server->httpRequest->getBody(true)); + + $properties = array( + 'href' => $uri, + 200 => array( + '{DAV:}getlastmodified' => new Sabre_DAV_Property_GetLastModified(filemtime($tempLocation)), + '{DAV:}getcontentlength' => filesize($tempLocation), + '{DAV:}resourcetype' => new Sabre_DAV_Property_ResourceType(null), + '{'.Sabre_DAV_Server::NS_SABREDAV.'}tempFile' => true, + + ), + ); + + $data = $this->server->generateMultiStatus(array($properties)); + $hR->sendBody($data); + return false; + + } + + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Tree.php b/3.0/modules/webdav/vendor/Sabre/DAV/Tree.php new file mode 100755 index 00000000..f7191e23 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Tree.php @@ -0,0 +1,192 @@ +getNodeForPath($path); + return true; + + } catch (Sabre_DAV_Exception_FileNotFound $e) { + + return false; + + } + + } + + /** + * Copies a file from path to another + * + * @param string $sourcePath The source location + * @param string $destinationPath The full destination path + * @return void + */ + public function copy($sourcePath, $destinationPath) { + + $sourceNode = $this->getNodeForPath($sourcePath); + + // grab the dirname and basename components + list($destinationDir, $destinationName) = Sabre_DAV_URLUtil::splitPath($destinationPath); + + $destinationParent = $this->getNodeForPath($destinationDir); + $this->copyNode($sourceNode,$destinationParent,$destinationName); + + $this->markDirty($destinationDir); + + } + + /** + * Moves a file from one location to another + * + * @param string $sourcePath The path to the file which should be moved + * @param string $destinationPath The full destination path, so not just the destination parent node + * @return int + */ + public function move($sourcePath, $destinationPath) { + + list($sourceDir, $sourceName) = Sabre_DAV_URLUtil::splitPath($sourcePath); + list($destinationDir, $destinationName) = Sabre_DAV_URLUtil::splitPath($destinationPath); + + if ($sourceDir===$destinationDir) { + $renameable = $this->getNodeForPath($sourcePath); + $renameable->setName($destinationName); + } else { + $this->copy($sourcePath,$destinationPath); + $this->getNodeForPath($sourcePath)->delete(); + } + $this->markDirty($sourceDir); + $this->markDirty($destinationDir); + + } + + /** + * Deletes a node from the tree + * + * @param string $path + * @return void + */ + public function delete($path) { + + $node = $this->getNodeForPath($path); + $node->delete(); + + list($parent) = Sabre_DAV_URLUtil::splitPath($path); + $this->markDirty($parent); + + } + + /** + * Returns a list of childnodes for a given path. + * + * @param string $path + * @return array + */ + public function getChildren($path) { + + $node = $this->getNodeForPath($path); + return $node->getChildren(); + + } + + /** + * This method is called with every tree update + * + * Examples of tree updates are: + * * node deletions + * * node creations + * * copy + * * move + * * renaming nodes + * + * If Tree classes implement a form of caching, this will allow + * them to make sure caches will be expired. + * + * If a path is passed, it is assumed that the entire subtree is dirty + * + * @param string $path + * @return void + */ + public function markDirty($path) { + + + } + + /** + * copyNode + * + * @param Sabre_DAV_INode $source + * @param Sabre_DAV_ICollection $destination + * @return void + */ + protected function copyNode(Sabre_DAV_INode $source,Sabre_DAV_ICollection $destinationParent,$destinationName = null) { + + if (!$destinationName) $destinationName = $source->getName(); + + if ($source instanceof Sabre_DAV_IFile) { + + $data = $source->get(); + + // If the body was a string, we need to convert it to a stream + if (is_string($data)) { + $stream = fopen('php://temp','r+'); + fwrite($stream,$data); + rewind($stream); + $data = $stream; + } + $destinationParent->createFile($destinationName,$data); + $destination = $destinationParent->getChild($destinationName); + + } elseif ($source instanceof Sabre_DAV_ICollection) { + + $destinationParent->createDirectory($destinationName); + + $destination = $destinationParent->getChild($destinationName); + foreach($source->getChildren() as $child) { + + $this->copyNode($child,$destination); + + } + + } + if ($source instanceof Sabre_DAV_IProperties && $destination instanceof Sabre_DAV_IProperties) { + + $props = $source->getProperties(array()); + $destination->updateProperties($props); + + } + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Tree/Filesystem.php b/3.0/modules/webdav/vendor/Sabre/DAV/Tree/Filesystem.php new file mode 100755 index 00000000..ee195eb2 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Tree/Filesystem.php @@ -0,0 +1,124 @@ +basePath = $basePath; + + } + + /** + * Returns a new node for the given path + * + * @param string $path + * @return void + */ + public function getNodeForPath($path) { + + $realPath = $this->getRealPath($path); + if (!file_exists($realPath)) throw new Sabre_DAV_Exception_FileNotFound('File at location ' . $realPath . ' not found'); + if (is_dir($realPath)) { + return new Sabre_DAV_FS_Directory($path); + } else { + return new Sabre_DAV_FS_File($path); + } + + } + + /** + * Returns the real filesystem path for a webdav url. + * + * @param string $publicPath + * @return string + */ + protected function getRealPath($publicPath) { + + return rtrim($this->basePath,'/') . '/' . trim($publicPath,'/'); + + } + + /** + * Copies a file or directory. + * + * This method must work recursively and delete the destination + * if it exists + * + * @param string $source + * @param string $destination + * @return void + */ + public function copy($source,$destination) { + + $source = $this->getRealPath($source); + $destination = $this->getRealPath($destination); + $this->realCopy($source,$destination); + + } + + /** + * Used by self::copy + * + * @param string $source + * @param string $destination + * @return void + */ + protected function realCopy($source,$destination) { + + if (is_file($source)) { + copy($source,$destination); + } else { + mkdir($destination); + foreach(scandir($source) as $subnode) { + + if ($subnode=='.' || $subnode=='..') continue; + $this->realCopy($source.'/'.$subnode,$destination.'/'.$subnode); + + } + } + + } + + /** + * Moves a file or directory recursively. + * + * If the destination exists, delete it first. + * + * @param string $source + * @param string $destination + * @return void + */ + public function move($source,$destination) { + + $source = $this->getRealPath($source); + $destination = $this->getRealPath($destination); + rename($source,$destination); + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/URLUtil.php b/3.0/modules/webdav/vendor/Sabre/DAV/URLUtil.php new file mode 100755 index 00000000..0dfc6896 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/URLUtil.php @@ -0,0 +1,141 @@ +=0x41 /* A */ && $c<=0x5a /* Z */) || + ($c>=0x61 /* a */ && $c<=0x7a /* z */) || + ($c>=0x30 /* 0 */ && $c<=0x39 /* 9 */) || + $c===0x5f /* _ */ || + $c===0x2d /* - */ || + $c===0x2e /* . */ || + $c===0x7E /* ~ */ || + + /* Reserved, but no reserved purpose */ + $c===0x28 /* ( */ || + $c===0x29 /* ) */ + + ) { + $newStr.=$pathSegment[$i]; + } else { + $newStr.='%' . str_pad(dechex($c), 2, '0', STR_PAD_LEFT); + } + + } + return $newStr; + + } + + /** + * Decodes a url-encoded path + * + * @param string $path + * @return string + */ + static function decodePath($path) { + + return self::decodePathSegment($path); + + } + + /** + * Decodes a url-encoded path segment + * + * @param string $path + * @return string + */ + static function decodePathSegment($path) { + + $path = urldecode($path); + $encoding = mb_detect_encoding($path, array('UTF-8','ISO-8859-1')); + + switch($encoding) { + + case 'ISO-8859-1' : + $path = utf8_encode($path); + } + + return $path; + + } + + /** + * Returns the 'dirname' and 'basename' for a path. + * + * The reason there is a custom function for this purpose, is because + * basename() is locale aware (behaviour changes if C locale or a UTF-8 locale is used) + * and we need a method that just operates on UTF-8 characters. + * + * In addition basename and dirname are platform aware, and will treat backslash (\) as a + * directory separator on windows. + * + * This method returns the 2 components as an array. + * + * If there is no dirname, it will return an empty string. Any / appearing at the end of the + * string is stripped off. + * + * @param string $path + * @return array + */ + static function splitPath($path) { + + $matches = array(); + if(preg_match('/^(?:(?:(.*)(?:\/+))?([^\/]+))(?:\/?)$/u',$path,$matches)) { + return array($matches[1],$matches[2]); + } else { + return array(null,null); + } + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/DAV/Version.php b/3.0/modules/webdav/vendor/Sabre/DAV/Version.php new file mode 100755 index 00000000..20584782 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/DAV/Version.php @@ -0,0 +1,24 @@ + + * will be returned as: + * {http://www.example.org}myelem + * + * This format is used throughout the SabreDAV sourcecode. + * Elements encoded with the urn:DAV namespace will + * be returned as if they were in the DAV: namespace. This is to avoid + * compatibility problems. + * + * This function will return null if a nodetype other than an Element is passed. + * + * @param DOMElement $dom + * @return string + */ + static function toClarkNotation(DOMNode $dom) { + + if ($dom->nodeType !== XML_ELEMENT_NODE) return null; + + // Mapping back to the real namespace, in case it was dav + if ($dom->namespaceURI=='urn:DAV') $ns = 'DAV:'; else $ns = $dom->namespaceURI; + + // Mapping to clark notation + return '{' . $ns . '}' . $dom->localName; + + } + + /** + * This method takes an XML document (as string) and converts all instances of the + * DAV: namespace to urn:DAV + * + * This is unfortunately needed, because the DAV: namespace violates the xml namespaces + * spec, and causes the DOM to throw errors + */ + static function convertDAVNamespace($xmlDocument) { + + // This is used to map the DAV: namespace to urn:DAV. This is needed, because the DAV: + // namespace is actually a violation of the XML namespaces specification, and will cause errors + return preg_replace("/xmlns(:[A-Za-z0-9_]*)?=(\"|\')DAV:(\\2)/","xmlns\\1=\\2urn:DAV\\2",$xmlDocument); + + } + + /** + * This method provides a generic way to load a DOMDocument for WebDAV use. + * + * This method throws a Sabre_DAV_Exception_BadRequest exception for any xml errors. + * It does not preserve whitespace, and it converts the DAV: namespace to urn:DAV. + * + * @param string $xml + * @throws Sabre_DAV_Exception_BadRequest + * @return DOMDocument + */ + static function loadDOMDocument($xml) { + + if (empty($xml)) + throw new Sabre_DAV_Exception_BadRequest('Empty XML document sent'); + + // The BitKinex client sends xml documents as UTF-16. PHP 5.3.1 (and presumably lower) + // does not support this, so we must intercept this and convert to UTF-8. + if (substr($xml,0,12) === "\x3c\x00\x3f\x00\x78\x00\x6d\x00\x6c\x00\x20\x00") { + + // Note: the preceeding byte sequence is "]*)encoding="UTF-16"([^>]*)>|u','',$xml); + + } + + // Retaining old error setting + $oldErrorSetting = libxml_use_internal_errors(true); + + // Clearing any previous errors + libxml_clear_errors(); + + $dom = new DOMDocument(); + $dom->loadXML(self::convertDAVNamespace($xml),LIBXML_NOWARNING | LIBXML_NOERROR); + + // We don't generally care about any whitespace + $dom->preserveWhiteSpace = false; + + if ($error = libxml_get_last_error()) { + libxml_clear_errors(); + throw new Sabre_DAV_Exception_BadRequest('The request body had an invalid XML body. (message: ' . $error->message . ', errorcode: ' . $error->code . ', line: ' . $error->line . ')'); + } + + // Restoring old mechanism for error handling + if ($oldErrorSetting===false) libxml_use_internal_errors(false); + + return $dom; + + } + + /** + * Parses all WebDAV properties out of a DOM Element + * + * Generally WebDAV properties are encloded in {DAV:}prop elements. This + * method helps by going through all these and pulling out the actual + * propertynames, making them array keys and making the property values, + * well.. the array values. + * + * If no value was given (self-closing element) null will be used as the + * value. This is used in for example PROPFIND requests. + * + * Complex values are supported through the propertyMap argument. The + * propertyMap should have the clark-notation properties as it's keys, and + * classnames as values. + * + * When any of these properties are found, the unserialize() method will be + * (statically) called. The result of this method is used as the value. + * + * @param DOMElement $parentNode + * @param array $propertyMap + * @return array + */ + static function parseProperties(DOMElement $parentNode, array $propertyMap = array()) { + + $propList = array(); + foreach($parentNode->childNodes as $propNode) { + + if (Sabre_DAV_XMLUtil::toClarkNotation($propNode)!=='{DAV:}prop') continue; + + foreach($propNode->childNodes as $propNodeData) { + + /* If there are no elements in here, we actually get 1 text node, this special case is dedicated to netdrive */ + if ($propNodeData->nodeType != XML_ELEMENT_NODE) continue; + + $propertyName = Sabre_DAV_XMLUtil::toClarkNotation($propNodeData); + if (isset($propertyMap[$propertyName])) { + $propList[$propertyName] = call_user_func(array($propertyMap[$propertyName],'unserialize'),$propNodeData); + } else { + $propList[$propertyName] = $propNodeData->textContent; + } + } + + + } + return $propList; + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/HTTP/AWSAuth.php b/3.0/modules/webdav/vendor/Sabre/HTTP/AWSAuth.php new file mode 100755 index 00000000..b97fea9d --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/HTTP/AWSAuth.php @@ -0,0 +1,226 @@ +httpRequest->getHeader('Authorization'); + $authHeader = explode(' ',$authHeader); + + if ($authHeader[0]!='AWS' || !isset($authHeader[1])) { + $this->errorCode = self::ERR_NOAWSHEADER; + return false; + } + + list($this->accessKey,$this->signature) = explode(':',$authHeader[1]); + + return true; + + } + + /** + * Returns the username for the request + * + * @return string + */ + public function getAccessKey() { + + return $this->accessKey; + + } + + /** + * Validates the signature based on the secretKey + * + * @return bool + */ + public function validate($secretKey) { + + $contentMD5 = $this->httpRequest->getHeader('Content-MD5'); + + if ($contentMD5) { + // We need to validate the integrity of the request + $body = $this->httpRequest->getBody(true); + $this->httpRequest->setBody($body,true); + + if ($contentMD5!=base64_encode(md5($body,true))) { + // content-md5 header did not match md5 signature of body + $this->errorCode = self::ERR_MD5CHECKSUMWRONG; + return false; + } + + } + + if (!$requestDate = $this->httpRequest->getHeader('x-amz-date')) + $requestDate = $this->httpRequest->getHeader('Date'); + + if (!$this->validateRFC2616Date($requestDate)) + return false; + + $amzHeaders = $this->getAmzHeaders(); + + $signature = base64_encode( + $this->hmacsha1($secretKey, + $this->httpRequest->getMethod() . "\n" . + $contentMD5 . "\n" . + $this->httpRequest->getHeader('Content-type') . "\n" . + $requestDate . "\n" . + $amzHeaders . + $this->httpRequest->getURI() + ) + ); + + if ($this->signature != $signature) { + + $this->errorCode = self::ERR_INVALIDSIGNATURE; + return false; + + } + + return true; + + } + + + /** + * Returns an HTTP 401 header, forcing login + * + * This should be called when username and password are incorrect, or not supplied at all + * + * @return void + */ + public function requireLogin() { + + $this->httpResponse->setHeader('WWW-Authenticate','AWS'); + $this->httpResponse->sendStatus(401); + + } + + /** + * Makes sure the supplied value is a valid RFC2616 date. + * + * If we would just use strtotime to get a valid timestamp, we have no way of checking if a + * user just supplied the word 'now' for the date header. + * + * This function also makes sure the Date header is within 15 minutes of the operating + * system date, to prevent replay attacks. + * + * @param string $dateHeader + * @return bool + */ + protected function validateRFC2616Date($dateHeader) { + + $date = Sabre_HTTP_Util::parseHTTPDate($dateHeader); + + // Unknown format + if (!$date) { + $this->errorCode = self::ERR_INVALIDDATEFORMAT; + return false; + } + + $min = new DateTime('-15 minutes'); + $max = new DateTime('+15 minutes'); + + // We allow 15 minutes around the current date/time + if ($date > $max || $date < $min) { + $this->errorCode = self::ERR_REQUESTTIMESKEWED; + return false; + } + + return $date; + + } + + /** + * Returns a list of AMZ headers + * + * @return void + */ + protected function getAmzHeaders() { + + $amzHeaders = array(); + $headers = $this->httpRequest->getHeaders(); + foreach($headers as $headerName => $headerValue) { + if (strpos(strtolower($headerName),'x-amz-')===0) { + $amzHeaders[strtolower($headerName)] = str_replace(array("\r\n"),array(' '),$headerValue) . "\n"; + } + } + ksort($amzHeaders); + + $headerStr = ''; + foreach($amzHeaders as $h=>$v) { + $headerStr.=$h.':'.$v; + } + + return $headerStr; + + } + + /** + * Generates an HMAC-SHA1 signature + * + * @param string $key + * @param string $message + * @return string + */ + private function hmacsha1($key, $message) { + + $blocksize=64; + if (strlen($key)>$blocksize) + $key=pack('H*', sha1($key)); + $key=str_pad($key,$blocksize,chr(0x00)); + $ipad=str_repeat(chr(0x36),$blocksize); + $opad=str_repeat(chr(0x5c),$blocksize); + $hmac = pack('H*',sha1(($key^$opad).pack('H*',sha1(($key^$ipad).$message)))); + return $hmac; + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/HTTP/AbstractAuth.php b/3.0/modules/webdav/vendor/Sabre/HTTP/AbstractAuth.php new file mode 100755 index 00000000..0abc4bcb --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/HTTP/AbstractAuth.php @@ -0,0 +1,111 @@ +httpResponse = new Sabre_HTTP_Response(); + $this->httpRequest = new Sabre_HTTP_Request(); + + } + + /** + * Sets an alternative HTTP response object + * + * @param Sabre_HTTP_Response $response + * @return void + */ + public function setHTTPResponse(Sabre_HTTP_Response $response) { + + $this->httpResponse = $response; + + } + + /** + * Sets an alternative HTTP request object + * + * @param Sabre_HTTP_Request $request + * @return void + */ + public function setHTTPRequest(Sabre_HTTP_Request $request) { + + $this->httpRequest = $request; + + } + + + /** + * Sets the realm + * + * The realm is often displayed in authentication dialog boxes + * Commonly an application name displayed here + * + * @param string $realm + * @return void + */ + public function setRealm($realm) { + + $this->realm = $realm; + + } + + /** + * Returns the realm + * + * @return string + */ + public function getRealm() { + + return $this->realm; + + } + + /** + * Returns an HTTP 401 header, forcing login + * + * This should be called when username and password are incorrect, or not supplied at all + * + * @return void + */ + abstract public function requireLogin(); + +} diff --git a/3.0/modules/webdav/vendor/Sabre/HTTP/BasicAuth.php b/3.0/modules/webdav/vendor/Sabre/HTTP/BasicAuth.php new file mode 100755 index 00000000..c0231b4e --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/HTTP/BasicAuth.php @@ -0,0 +1,61 @@ +httpRequest->getRawServerValue('PHP_AUTH_USER')) && ($pass = $this->httpRequest->getRawServerValue('PHP_AUTH_PW'))) { + + return array($user,$pass); + + } + + // Most other webservers + $auth = $this->httpRequest->getHeader('Authorization'); + + if (!$auth) return false; + + if (strpos(strtolower($auth),'basic')!==0) return false; + + return explode(':', base64_decode(substr($auth, 6))); + + } + + /** + * Returns an HTTP 401 header, forcing login + * + * This should be called when username and password are incorrect, or not supplied at all + * + * @return void + */ + public function requireLogin() { + + $this->httpResponse->setHeader('WWW-Authenticate','Basic realm="' . $this->realm . '"'); + $this->httpResponse->sendStatus(401); + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/HTTP/DigestAuth.php b/3.0/modules/webdav/vendor/Sabre/HTTP/DigestAuth.php new file mode 100755 index 00000000..bce59594 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/HTTP/DigestAuth.php @@ -0,0 +1,234 @@ +nonce = uniqid(); + $this->opaque = md5($this->realm); + parent::__construct(); + + } + + /** + * Gathers all information from the headers + * + * This method needs to be called prior to anything else. + * + * @return void + */ + public function init() { + + $digest = $this->getDigest(); + $this->digestParts = $this->parseDigest($digest); + + } + + /** + * Sets the quality of protection value. + * + * Possible values are: + * Sabre_HTTP_DigestAuth::QOP_AUTH + * Sabre_HTTP_DigestAuth::QOP_AUTHINT + * + * Multiple values can be specified using logical OR. + * + * QOP_AUTHINT ensures integrity of the request body, but this is not + * supported by most HTTP clients. QOP_AUTHINT also requires the entire + * request body to be md5'ed, which can put strains on CPU and memory. + * + * @param int $qop + * @return void + */ + public function setQOP($qop) { + + $this->qop = $qop; + + } + + /** + * Validates the user. + * + * The A1 parameter should be md5($username . ':' . $realm . ':' . $password); + * + * @param string $A1 + * @return bool + */ + public function validateA1($A1) { + + $this->A1 = $A1; + return $this->validate(); + + } + + /** + * Validates authentication through a password. The actual password must be provided here. + * It is strongly recommended not store the password in plain-text and use validateA1 instead. + * + * @param string $password + * @return bool + */ + public function validatePassword($password) { + + $this->A1 = md5($this->digestParts['username'] . ':' . $this->realm . ':' . $password); + return $this->validate(); + + } + + /** + * Returns the username for the request + * + * @return string + */ + public function getUsername() { + + return $this->digestParts['username']; + + } + + /** + * Validates the digest challenge + * + * @return bool + */ + protected function validate() { + + $A2 = $this->httpRequest->getMethod() . ':' . $this->digestParts['uri']; + + if ($this->digestParts['qop']=='auth-int') { + // Making sure we support this qop value + if (!($this->qop & self::QOP_AUTHINT)) return false; + // We need to add an md5 of the entire request body to the A2 part of the hash + $body = $this->httpRequest->getBody(true); + $this->httpRequest->setBody($body,true); + $A2 .= ':' . md5($body); + } else { + + // We need to make sure we support this qop value + if (!($this->qop & self::QOP_AUTH)) return false; + } + + $A2 = md5($A2); + + $validResponse = md5("{$this->A1}:{$this->digestParts['nonce']}:{$this->digestParts['nc']}:{$this->digestParts['cnonce']}:{$this->digestParts['qop']}:{$A2}"); + + return $this->digestParts['response']==$validResponse; + + + } + + /** + * Returns an HTTP 401 header, forcing login + * + * This should be called when username and password are incorrect, or not supplied at all + * + * @return void + */ + public function requireLogin() { + + $qop = ''; + switch($this->qop) { + case self::QOP_AUTH : $qop = 'auth'; break; + case self::QOP_AUTHINT : $qop = 'auth-int'; break; + case self::QOP_AUTH | self::QOP_AUTHINT : $qop = 'auth,auth-int'; break; + } + + $this->httpResponse->setHeader('WWW-Authenticate','Digest realm="' . $this->realm . '",qop="'.$qop.'",nonce="' . $this->nonce . '",opaque="' . $this->opaque . '"'); + $this->httpResponse->sendStatus(401); + + } + + + /** + * This method returns the full digest string. + * + * It should be compatibile with mod_php format and other webservers. + * + * If the header could not be found, null will be returned + * + * @return mixed + */ + public function getDigest() { + + // mod_php + $digest = $this->httpRequest->getRawServerValue('PHP_AUTH_DIGEST'); + if ($digest) return $digest; + + // most other servers + $digest = $this->httpRequest->getHeader('Authorization'); + + if ($digest && strpos(strtolower($digest),'digest')===0) { + return substr($digest,7); + } else { + return null; + } + + } + + + /** + * Parses the different pieces of the digest string into an array. + * + * This method returns false if an incomplete digest was supplied + * + * @param string $digest + * @return mixed + */ + protected function parseDigest($digest) { + + // protect against missing data + $needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1); + $data = array(); + + preg_match_all('@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', $digest, $matches, PREG_SET_ORDER); + + foreach ($matches as $m) { + $data[$m[1]] = $m[2] ? $m[2] : $m[3]; + unset($needed_parts[$m[1]]); + } + + return $needed_parts ? false : $data; + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/HTTP/Request.php b/3.0/modules/webdav/vendor/Sabre/HTTP/Request.php new file mode 100755 index 00000000..8a0059bc --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/HTTP/Request.php @@ -0,0 +1,220 @@ +_SERVER = $serverData; + else $this->_SERVER =& $_SERVER; + + } + + /** + * Returns the value for a specific http header. + * + * This method returns null if the header did not exist. + * + * @param string $name + * @return string + */ + public function getHeader($name) { + + $serverName = 'HTTP_' . strtoupper(str_replace(array('-'),array('_'),$name)); + return isset($this->_SERVER[$serverName])?$this->_SERVER[$serverName]:null; + + } + + /** + * Returns all (known) HTTP headers. + * + * All headers are converted to lower-case, and additionally all underscores + * are automatically converted to dashes + * + * @return array + */ + public function getHeaders() { + + $hdrs = array(); + foreach($this->_SERVER as $key=>$value) { + + if (strpos($key,'HTTP_')===0) { + $hdrs[substr(strtolower(str_replace('_','-',$key)),5)] = $value; + } + + } + + return $hdrs; + + } + + /** + * Returns the HTTP request method + * + * This is for example POST or GET + * + * @return string + */ + public function getMethod() { + + return $this->_SERVER['REQUEST_METHOD']; + + } + + /** + * Returns the requested uri + * + * @return string + */ + public function getUri() { + + return $this->_SERVER['REQUEST_URI']; + + } + + /** + * Will return protocol + the hostname + the uri + * + * @return void + */ + public function getAbsoluteUri() { + + // Checking if the request was made through HTTPS. The last in line is for IIS + $protocol = isset($this->_SERVER['HTTPS']) && ($this->_SERVER['HTTPS']) && ($this->_SERVER['HTTPS']!='off'); + return ($protocol?'https':'http') . '://' . $this->getHeader('Host') . $this->getUri(); + + } + + /** + * Returns everything after the ? from the current url + * + * @return string + */ + public function getQueryString() { + + return isset($this->_SERVER['QUERY_STRING'])?$this->_SERVER['QUERY_STRING']:''; + + } + + /** + * Returns the HTTP request body body + * + * This method returns a readable stream resource. + * If the asString parameter is set to true, a string is sent instead. + * + * @param bool asString + * @return resource + */ + public function getBody($asString = false) { + + if (is_null($this->body)) { + if (!is_null(self::$defaultInputStream)) { + $this->body = self::$defaultInputStream; + } else { + $this->body = fopen('php://input','r'); + self::$defaultInputStream = $this->body; + } + } + if ($asString) { + $body = stream_get_contents($this->body); + return $body; + } else { + return $this->body; + } + + } + + /** + * Sets the contents of the HTTP requet body + * + * This method can either accept a string, or a readable stream resource. + * + * If the setAsDefaultInputStream is set to true, it means for this run of the + * script the supplied body will be used instead of php://input. + * + * @param mixed $body + * @param bool $setAsDefaultInputStream + * @return void + */ + public function setBody($body,$setAsDefaultInputStream = false) { + + if(is_resource($body)) { + $this->body = $body; + } else { + + $stream = fopen('php://temp','r+'); + fputs($stream,$body); + rewind($stream); + // String is assumed + $this->body = $stream; + } + if ($setAsDefaultInputStream) { + self::$defaultInputStream = $this->body; + } + + } + + /** + * Returns a specific item from the _SERVER array. + * + * Do not rely on this feature, it is for internal use only. + * + * @param string $field + * @return string + */ + public function getRawServerValue($field) { + + return isset($this->_SERVER[$field])?$this->_SERVER[$field]:null; + + } + +} + diff --git a/3.0/modules/webdav/vendor/Sabre/HTTP/Response.php b/3.0/modules/webdav/vendor/Sabre/HTTP/Response.php new file mode 100755 index 00000000..15a26874 --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/HTTP/Response.php @@ -0,0 +1,151 @@ + 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', + 200 => 'Ok', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authorative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-Status', // RFC 4918 + 208 => 'Already Reported', // RFC 5842 + 226 => 'IM Used', // RFC 3229 + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 306 => 'Reserved', + 307 => 'Temporary Redirect', + 400 => 'Bad request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 418 => 'I\'m a teapot', // RFC 2324 + 422 => 'Unprocessable Entity', // RFC 4918 + 423 => 'Locked', // RFC 4918 + 424 => 'Failed Dependency', // RFC 4918 + 426 => 'Upgrade required', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version not supported', + 506 => 'Variant Also Negotiates', + 507 => 'Unsufficient Storage', // RFC 4918 + 508 => 'Loop Detected', // RFC 5842 + 510 => 'Not extended', + ); + + return 'HTTP/1.1 ' . $code . ' ' . $msg[$code]; + + } + + /** + * Sends an HTTP status header to the client + * + * @param int $code HTTP status code + * @return void + */ + public function sendStatus($code) { + + if (!headers_sent()) + return header($this->getStatusMessage($code)); + else return false; + + } + + /** + * Sets an HTTP header for the response + * + * @param string $name + * @param string $value + * @return void + */ + public function setHeader($name, $value, $replace = true) { + + $value = str_replace(array("\r","\n"),array('\r','\n'),$value); + if (!headers_sent()) + return header($name . ': ' . $value, $replace); + else return false; + + } + + /** + * Sets a bunch of HTTP Headers + * + * headersnames are specified as keys, value in the array value + * + * @param array $headers + * @return void + */ + public function setHeaders(array $headers) { + + foreach($headers as $key=>$value) + $this->setHeader($key, $value); + + } + + /** + * Sends the entire response body + * + * This method can accept either an open filestream, or a string. + * + * @param mixed $body + * @return void + */ + public function sendBody($body) { + + if (is_resource($body)) { + + fpassthru($body); + + } else { + + // We assume a string + echo $body; + + } + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/HTTP/Util.php b/3.0/modules/webdav/vendor/Sabre/HTTP/Util.php new file mode 100755 index 00000000..02ae1c0f --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/HTTP/Util.php @@ -0,0 +1,65 @@ += 0) + return new DateTime('@' . $realDate, new DateTimeZone('UTC')); + + return false; + + } + +} diff --git a/3.0/modules/webdav/vendor/Sabre/HTTP/Version.php b/3.0/modules/webdav/vendor/Sabre/HTTP/Version.php new file mode 100755 index 00000000..5372a49c --- /dev/null +++ b/3.0/modules/webdav/vendor/Sabre/HTTP/Version.php @@ -0,0 +1,24 @@ +load_theme_info(); - return ($theme_info->version); - } - - private function get_theme_name() { - $theme_info = $this->load_theme_info(); - return ($theme_info->name); - } - - private function get_colorpacks() { - $colorpacks = array(); - $colorpackroot = THEMEPATH . 'greydragon/css/colorpacks/'; - - foreach (scandir($colorpackroot) as $colorpack_name): - if (file_exists($colorpackroot . "$colorpack_name/colors.css")): - if ($colorpack_name[0] == "."): - continue; - endif; - - $colorpacks[$colorpack_name] = t($colorpack_name); - endif; - endforeach; - return $colorpacks; - } - - private function prerequisite_check($group, $id, $is_ok, $caption, $caption_ok, $caption_failed, $iswarning, $msg_error) { - - $confirmation_caption = ($is_ok)? $caption_ok : $caption_failed; - $checkbox = $group->checkbox($id) - ->label($caption . " " . $confirmation_caption) - ->checked($is_ok) - ->disabled(true); - if ($is_ok): - $checkbox->class("g-success"); - elseif ($iswarning): - $checkbox->class("g-prerequisite g-warning")->error_messages("failed", $msg_error)->add_error("failed", 1); - else: - $checkbox->class("g-error")->error_messages("failed", $msg_error)->add_error("failed", 1); - endif; - } - - protected function get_edit_form_admin() { - $form = new Forge("admin/theme_options/save/", "", null, array("id" =>"g-theme-options-form")); - - $group = $form->group("requirements")->label("Prerequisites Checklist"); - $gallery_ver = module::get_version("gallery"); - - $this->prerequisite_check($group, "vercheck", $gallery_ver >= $this->min_gallery_ver, - t("Gallery 3 Core v.") . $this->min_gallery_ver, "Installed", "Required", FALSE, t("Check Failed. Minimum Required Version") . " " . $gallery_ver); - - $this->prerequisite_check($group, "shadowbox", ((module::is_active("shadowbox")) and (module::info("shadowbox"))), - t("Shadowbox Module"), "Found", "Required", FALSE, t("Check Failed. Shadowbox Module not Installed.")); - - if (!module::get_var("th_greydragon", "hide_thumbmeta")): - $this->prerequisite_check($group, "info", (module::is_active("info") and module::info("info")), - t("Info Module"), "Found", "Required", FALSE, t("Check Failed. Module is required to display Thumb metadata.")); - endif; - - $group = $form->group("recommended")->label("Module Recommendations"); - - $organize_active = ((module::is_active("organize")) and (module::info("organize"))); - $this->prerequisite_check($group, "organizecheck", !$organize_active, - t("Organize Module"), "not Used", "Found", TRUE, t("Default Organize module is active but is not supported in full by the theme.")); - - $kbdnav_active = ((module::is_active("kbd_nav")) and (module::info("kbd_nav"))); - $this->prerequisite_check($group, "kbdnavcheck", $kbdnav_active, - t("Kbd Navigation Module"), "Found", "not Found", TRUE, t('Install module to enable keyboard navigation support.')); - - $sidebar_allowed = module::get_var("th_greydragon", "sidebar_allowed"); - $sidebar_visible = module::get_var("th_greydragon", "sidebar_visible"); - - $pagesize = module::get_var("gallery", "page_size"); - if (($sidebar_allowed == "none") and ($sidebar_visible == "none")): - $pagesize = $pagesize / 4; - else: - $pagesize = $pagesize / 3; - endif; - - $group = $form->group("edit_theme")->label(t("General Settings")); - $group->input("row_count") - ->label(t("Rows per Album Page")) - ->rules("required|valid_digit") - ->error_messages("required", t("You must enter a number")) - ->error_messages("valid_digit", t("You must enter a number")) - ->value($pagesize); - $group->input("resize_size") - ->label(t("Resized Image Size (in pixels)")) - ->rules("required|valid_digit") - ->error_messages("required", t("You must enter a number")) - ->error_messages("valid_digit", t("You must enter a number")) - ->value(module::get_var("gallery", "resize_size")); - $group->input("logo_path") - ->label(t("Alternate Logo Image")) - ->value(module::get_var("th_greydragon", "logo_path")); - $group->input("header_text") - ->label(t("Header Text")) - ->value(module::get_var("gallery", "header_text")); - $group->input("footer_text") - ->label(t("Footer Text")) - ->value(module::get_var("gallery", "footer_text")); - $group->input("copyright") - ->label(t("Copyright Message")) - ->value(module::get_var("th_greydragon", "copyright")); - $group->dropdown("colorpack") - ->label(t("Selected Color Pack")) - ->options(self::get_colorpacks()) - ->selected(module::get_var("th_greydragon", "color_pack", "greydragon")); - - $group = $form->group("edit_theme_adv_main")->label(t("Advanced Options - Main")); - $group->checkbox("show_credits") - ->label(t("Show Site Credits")) - ->checked(module::get_var("gallery", "show_credits")); - $group->checkbox("show_guest_menu") - ->label(t("Show Main Menu for Guest Users")) - ->checked(module::get_var("th_greydragon", "show_guest_menu")); - $group->checkbox("loginmenu_position") - ->label(t("Place Login Link in the Header")) - ->checked(module::get_var("th_greydragon", "loginmenu_position") == "header"); - $group->checkbox("mainmenu_position") - ->label(t("Alternate Header Layout")) - ->checked(module::get_var("th_greydragon", "mainmenu_position") == "top"); - $group->checkbox("hide_breadcrumbs") - ->label(t("Hide Breadcrumbs")) - ->checked(module::get_var("th_greydragon", "hide_breadcrumbs")); - $group->dropdown("photonav_position") - ->label(t("Item Navigator Position")) - ->options(array("top" => t("Top"), "bottom" => t("Bottom"), "both" => t("Both"), "none" => t("None"))) - ->selected(module::get_var("th_greydragon", "photonav_position")); - $group->checkbox("disable_seosupport") - ->label(t("Disallow Search Engine Indexing")) - ->checked(module::get_var("th_greydragon", "disable_seosupport")); - $group->checkbox("enable_pagecache") - ->label(t("Enable Page Cache (60 seconds)")) - ->checked(module::get_var("th_greydragon", "enable_pagecache")); - - $group = $form->group("edit_theme_adv_thumb")->label(t("Advanced Options - Album page/Thumbs")); - $group->dropdown("thumb_ratio") - ->label(t("Aspect Ratio")) - ->options(array("photo" => t("Actual Size"), "digital" => t("Digital 4:3"), "film" => t("Film 3:2") /* , "square" => t("Square 1:1") */ )) - ->selected(module::get_var("th_greydragon", "thumb_ratio")); - $group->dropdown("thumb_descmode") - ->label(t("Title Display Mode")) - ->options(array("overlay" => t("Overlay"), "bottom" => t("Bottom"), "hide" => t("Hide"))) - ->selected(module::get_var("th_greydragon", "thumb_descmode")); - $group->checkbox("hide_thumbmeta") - ->label(t("Hide Item Meta Data")) - ->checked(module::get_var("th_greydragon", "hide_thumbmeta")); - - $group = $form->group("edit_theme_adv_photo")->label(t("Advanced Options - Photo page")); - $group->dropdown("photo_descmode") - ->label(t("Description Display Mode")) - ->options(array("overlay" => t("Overlay"), "bottom" => t("Bottom"), "top" => t("Top"), "hide" => t("Hide"))) - ->selected(module::get_var("th_greydragon", "photo_descmode")); - $group->checkbox("desc_allowbbcode") - ->label(t("Allow BBCode/HTML in Descriptions")) - ->checked(module::get_var("th_greydragon", "desc_allowbbcode")); - $group->checkbox("hide_photometa") - ->label(t("Hide Item Meta Data")) - ->checked(module::get_var("th_greydragon", "hide_photometa", TRUE)); - - $group = $form->group("edit_theme_side")->label(t("Sidebar Options")); - $group->checkbox("hide_blockheader") - ->label(t("Hide Block Header")) - ->checked(module::get_var("th_greydragon", "hide_blockheader")); - $group->checkbox("sidebar_albumonly") - ->label(t("Show Sidebar for Albums Only")) - ->checked(module::get_var("th_greydragon", "sidebar_albumonly")); - $group->dropdown("sidebar_allowed") - ->label(t("Allowed Sidebar Positions")) - ->options(array("any" => t("Any"), "left" => t("Left"), "right" => t("Right"), "none" => t("Default Only"))) - ->selected($sidebar_allowed); - $group->dropdown("sidebar_visible") - ->label(t("Default Sidebar Position")) - ->options(array("right" => t("Right"), "left" => t("Left"), "none" => t("No sidebar"))) - ->selected($sidebar_visible); - - $group = $form->group("maintenance")->label("Maintenance"); - $group->checkbox("build_resize")->label(t("Mark all Image Resizes for Rebuild"))->checked(false); - $group->checkbox("build_thumbs")->label(t("Mark all Thumbnails for Rebuild"))->checked(false); - $group->checkbox("build_exif")->label(t("Reset Exif Info"))->checked(false); - $group->checkbox("reset_theme")->label(t("Reset Theme to a Default State"))->checked(false); - - module::event("theme_edit_form", $form); - - $form->submit("g-theme-options-save")->value(t("Save Changes")); - - return $form; - } - - protected function get_edit_form_help() { - $help = '
'; - $help .= 'Help
    '; - $help .= '
  • Prerequisites

    -

    Requirements need to be met for theme to function properly.

    -

    If indicated please download and install - Shadowbox module. Module is required to properly display photos in maximized view and for any admin operations dialogs.

    -
  • '; - - $help .= '
  • Module Recommendations

    -

    Some recommendations to make your experience with the theme more pleasant.

    -

    While there is some support for default Organize module, theme may not skin it properly all the way. - Please consider using GWT Organize Module instead.

    -

    Enable Keyboard navigation by installing Kbd Navigation Module.

    -
  • '; - - $help .= '
  • General Settings

    -

    Theme is designed to display thumbnails in fixed 3+sidebar or 4 columns format. - Number of Rows per Album Page however can be adjusted.
    - Unlike in default theme, thumbnails size is restricted to max 200x200px.

    -

    Default G3 logo can be replaced with your own by providing Alternate Logo Image. - Recommended logo size is within 300x80px. If you need bigger space for your logo, CSS would have to be adjusted.

    -

    Logo could be suppressed altogether by providing Header Text which would take its place. - Footer Text would be simply placed next to Site\'s credits.

    -

    To indicate your rights for the artwork displayed Copyright Message can be placed in - right top corner of the footer.

    -

    Important feature of the theme is ability to specify Selected Color Pack. Color Pack is small CSS - file which defines color rules for the theme. By default theme comes with GreyDragon (default) and Wind sets, - but it could be easily extended. Visit our Download page for additional information.

    -
  • '; - $help .= '
  • Advanced Options

    -

    Show Site Credits simply shows appreciation for hard work of G3 team and Theme\'s author - (you could do also do this by clicking Donate link above).

    -

    If main menu has functionality intended for guest users you can use Show Main Menu for Guest Users - to keep it visible.

    -

    If you do not like login link in the footer you can move it into top right corner by selecting Place Login Link in the Header.

    -

    You can go even further and move main menu to the top of the header with breadcrumbs taking it place by selecting Alternate Header Layout.

    -

    Item Navigator Position could be changed to display it above and/or below the main content.

    -

    Thumb: Aspect Ratio should be used with understanding that some information - may be out of visible area in photo thumbs. Based on specified aspect all thumbs sizes would be adjusted - accordingly. When switching to/from Actual Size, it is recommended to rebuild thumbs for proper display - (see Maintenance section below).

    -

    If you prefer including Item\'s caption as part of the thumb, you can use Thumb: Title Display Mode to change - default Overlay mode. And if metadata (owner/clicks) is not necessary, it could be hidden with Thumb: Hide Item Meta Data.

    -

    Similar to Thumb option above Item\'s description could be displayed where available. - In non-Overlay mode, this is not limited to just Photo page, but description could be - displayed for albums also.

    -
  • '; - $help .= '
  • Sidebar Options

    -

    If Block\'s header is not desired, it could be removed using Hide Block Header.

    -

    Sidebar visibility could be limited to individual Photo pages with - Show Sidebar for Albums Only. -

    When sidebar is visible it can be placed on the left or right of the - screen or removed altogether using Allowed Sidebar Positions. - If more than one position is allowed, Default Sidebar Position - would indicate default state, but visitor would able change it later. -

  • '; - $help .= '
  • Maintenance

    -

    Without changing image size, you can Mark all Resizes for Rebuild. - Then you need to visit Admin\Maintenance to initiate the process. -

    Same can be done for image thumbs with Mark all Thumbnails for Rebuild. -

    Reset Exif Info would remove all exif info allowing it to be imported again.

    -

    And just in case you think that something is not right, you can - always Reset Theme to a Default State. -

  • '; - $help .= '
'; - return $help; - } - - private function save_item_state($statename, $state, $value) { - if ($state): - module::set_var("th_greydragon", $statename, $value); - else: - module::clear_var("th_greydragon", $statename); - endif; - } - - public function save() { - site_status::clear("gd_init_configuration"); - access::verify_csrf(); - - $form = self::get_edit_form_admin(); - if ($form->validate()): - module::clear_var("th_greydragon", "photonav_top"); - module::clear_var("th_greydragon", "photonav_bottom"); - module::clear_var("th_greydragon", "hide_sidebar_photo"); - module::clear_var("th_greydragon", "hide_thumbdesc"); - module::clear_var("th_greydragon", "use_detailview"); - - if ($form->maintenance->reset_theme->value): - module::set_var("gallery", "page_size", 9); - module::set_var("gallery", "resize_size", 640); - module::set_var("gallery", "thumb_size", 200); - - module::set_var("gallery", "header_text", ""); - module::set_var("gallery", "footer_text", ""); - module::clear_var("th_greydragon", "copyright"); - module::clear_var("th_greydragon", "logo_path"); - module::clear_var("th_greydragon", "color_pack"); - - module::clear_var("th_greydragon", "enable_pagecache"); - module::set_var("gallery", "show_credits", FALSE); - module::clear_var("th_greydragon", "show_guest_menu"); - module::clear_var("th_greydragon", "mainmenu_position"); - module::clear_var("th_greydragon", "loginmenu_position"); - module::clear_var("th_greydragon", "hide_breadcrumbs"); - module::clear_var("th_greydragon", "horizontal_crop"); - module::clear_var("th_greydragon", "thumb_descmode"); - module::clear_var("th_greydragon", "hide_thumbmeta"); - module::clear_var("th_greydragon", "hide_blockheader"); - module::clear_var("th_greydragon", "photonav_position"); - module::clear_var("th_greydragon", "photo_descmode"); - module::clear_var("th_greydragon", "desc_allowbbcode"); - module::clear_var("th_greydragon", "hide_photometa"); - module::clear_var("th_greydragon", "disable_seosupport"); - - module::clear_var("th_greydragon", "sidebar_albumonly"); - module::clear_var("th_greydragon", "sidebar_allowed"); - module::clear_var("th_greydragon", "sidebar_visible"); - - module::event("theme_edit_form_completed", $form); - message::success(t("Theme details are reset")); - else: - // * General Settings **************************************************** - - $_priorratio = module::get_var("th_greydragon", "thumb_ratio"); - if (!$_priorratio): - $_priorratio = "digital"; - endif; - - $resize_size = $form->edit_theme->resize_size->value; - $thumb_size = 200; - - $build_resize = $form->maintenance->build_resize->value; - $build_thumbs = $form->maintenance->build_thumbs->value; - $build_exif = $form->maintenance->build_exif->value; - - $thumb_ratio = $form->edit_theme_adv_thumb->thumb_ratio->value; - if ($thumb_ratio == "photo") { $rule = Image::AUTO; } else { $rule = Image::WIDTH; } - $color_pack = $form->edit_theme->colorpack->value; - $thumb_descmode = $form->edit_theme_adv_thumb->thumb_descmode->value; - $photo_descmode = $form->edit_theme_adv_photo->photo_descmode->value; - - if ($build_resize): - graphics::remove_rule("gallery", "resize", "gallery_graphics::resize"); - graphics::add_rule("gallery", "resize", "gallery_graphics::resize", - array("width" => $resize_size, "height" => $resize_size, "master" => Image::AUTO), 100); - endif; - if (module::get_var("gallery", "resize_size") != $resize_size): - module::set_var("gallery", "resize_size", $resize_size); - endif; - - if ($build_thumbs): - graphics::remove_rule("gallery", "thumb", "gallery_graphics::resize"); - graphics::add_rule("gallery", "thumb", "gallery_graphics::resize", - array("width" => $thumb_size, "height" => $thumb_size, "master" => $rule), 100); - endif; - - if ($build_exif): - db::build() - ->delete("exif_records") - ->execute(); - endif; - - if (module::get_var("gallery", "thumb_size") != $thumb_size): - module::set_var("gallery", "thumb_size", $thumb_size); - endif; - module::set_var("gallery", "header_text", $form->edit_theme->header_text->value); - module::set_var("gallery", "footer_text", $form->edit_theme->footer_text->value); - $this->save_item_state("copyright", $form->edit_theme->copyright->value, $form->edit_theme->copyright->value); - $this->save_item_state("logo_path", $form->edit_theme->logo_path->value, $form->edit_theme->logo_path->value); - $this->save_item_state("color_pack", (($color_pack) and ($color_pack != "greydragon")), $color_pack); - - // * Advanced Options - main ********************************************* - - module::set_var("gallery", "show_credits", $form->edit_theme_adv_main->show_credits->value); - $this->save_item_state("show_guest_menu", $form->edit_theme_adv_main->show_guest_menu->value, TRUE); - $this->save_item_state("loginmenu_position", $form->edit_theme_adv_main->loginmenu_position->value == "1", "header"); - $this->save_item_state("mainmenu_position", $form->edit_theme_adv_main->mainmenu_position->value == "1", "top"); - $this->save_item_state("hide_breadcrumbs", $form->edit_theme_adv_main->hide_breadcrumbs->value, TRUE); - $this->save_item_state("photonav_position", $form->edit_theme_adv_main->photonav_position->value != "top", $form->edit_theme_adv->photonav_position->value); - $this->save_item_state("enable_pagecache", $form->edit_theme_adv_main->enable_pagecache->value, TRUE); - $this->save_item_state("disable_seosupport", $form->edit_theme_adv_main->disable_seosupport->value, TRUE); - - // * Advanced Options - Album page *************************************** - - $this->save_item_state("thumb_ratio", $thumb_ratio != "photo", $thumb_ratio); - $this->save_item_state("thumb_descmode", $thumb_descmode != "overlay", $thumb_descmode); - $this->save_item_state("hide_thumbmeta", $form->edit_theme_adv_thumb->hide_thumbmeta->value, TRUE); - - // * Advanced Options - Photo page *************************************** - - $this->save_item_state("photo_descmode", $photo_descmode != "overlay", $photo_descmode); - $this->save_item_state("desc_allowbbcode", $form->edit_theme_adv_photo->desc_allowbbcode->value, TRUE); - $this->save_item_state("hide_photometa", !$form->edit_theme_adv_photo->hide_photometa->value, FALSE); - - // * Sidebar Options **************************************************** - - $sidebar_allowed = $form->edit_theme_side->sidebar_allowed->value; - $sidebar_visible = $form->edit_theme_side->sidebar_visible->value; - - if ($sidebar_allowed == "right"): - $sidebar_visible = "right"; - endif; - if ($sidebar_allowed == "left"): - $sidebar_visible = "left"; - endif; - - $this->save_item_state("hide_blockheader", $form->edit_theme_side->hide_blockheader->value, TRUE); - $this->save_item_state("sidebar_albumonly", $form->edit_theme_side->sidebar_albumonly->value, TRUE); - $this->save_item_state("sidebar_allowed", $sidebar_allowed != "any", $sidebar_allowed); - $this->save_item_state("sidebar_visible", $sidebar_visible != "right", $sidebar_visible); - - if (($sidebar_allowed == "none") and ($sidebar_visible == "none")): - module::set_var("gallery", "page_size", $form->edit_theme->row_count->value * 4); - else: - module::set_var("gallery", "page_size", $form->edit_theme->row_count->value * 3); - endif; - - module::event("theme_edit_form_completed", $form); - - if ($_priorratio != $thumb_ratio): - message::warning(t("Thumb aspect ratio has been changed. Consider rebuilding thumbs if needed.")); - endif; - - message::success(t("Updated theme details")); - endif; - - url::redirect("admin/theme_options"); - else: - $view = new Admin_View("admin.html"); - $view->content = $form; - print $view; - endif; - } - - public function index() { - site_status::clear("gd_init_configuration"); - - $view = new Admin_View("admin.html"); - $view->page_title = t("Grey Dragon Theme"); - $view->content = new View("admin_theme_options.html"); - $view->content->name = self::get_theme_name(); - $view->content->version = self::get_theme_version(); - $view->content->form = self::get_edit_form_admin(); - $view->content->help = self::get_edit_form_help(); - print $view; - } -} diff --git a/3.0/themes/greydragon/admin/views/admin_theme_options.html.php b/3.0/themes/greydragon/admin/views/admin_theme_options.html.php deleted file mode 100644 index 6c919461..00000000 --- a/3.0/themes/greydragon/admin/views/admin_theme_options.html.php +++ /dev/null @@ -1,59 +0,0 @@ - - - - -
-
-
-
- -
-
- -
-
- -
-
diff --git a/3.0/themes/greydragon/changelog.txt b/3.0/themes/greydragon/changelog.txt deleted file mode 100644 index 3d5a1451..00000000 --- a/3.0/themes/greydragon/changelog.txt +++ /dev/null @@ -1,239 +0,0 @@ -=== Grey Dragon Theme === -Grey Dragon Theme - a custom theme for Gallery 3 - -This theme was designed and built by Serguei Dosyukov, whose blog you will find at http://blog.dragonsoft.us/ -Copyright (C) 2009-2010 Serguei Dosyukov - -Tested up to: G3 3.0 RC2 (Santa Fe) Experimental -Minimum requirement: G3 3.0 RC2 (Santa Fe) Experimental -Donate link: http://blog.dragonsoft.us/gallery-3/ - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street Fifth Floor, Boston, MA 02110-1301, USA. - -=== Open issues === -- Issue with Delete functionality -- Support for new organize module -- Support for Register module -- Issue with Comments module - -=== Changelog === - -version 2.3.1 -- Hide Rotate operations for pictures since they are not supported by the theme -- Added use of common gallery.ajax.js. Fix issue with some Ajax based links. -- Layout fixes for Translation form overlay -- Changed CSS styling for buttons to provide unified coverage for buttons and links exposed as buttons. -- ADMIN: Fixed options group styles in Theme's Admin panel -- ADMIN: Advanced Settings for Thumbs and Individual Photo are moved into separate sections. -- ADMIN: New option - display meta data in Photo description section -- ADMIN: New option/fix - SEO indexing is now allowed by default. In order to prevent your site from being indexed, you can now use "Disallow Search Engine Indexing" option - -version 2.3.0 -- Adopted for Gallery 3.0RC2 changes (minor template adjustments, css class name changes, etc.) - -version 2.2.1 -- Redesigned Ready event handler for the theme to ensure proper ShadowBox initialization -- Added support for gallery_dialog() function call used by some 3rd party modules - some sync issues are solved by imposed delay of 1 second -- GPS module - better action list alignment in the sidebar - -version 2.2.0 -- Added support for slideshow mode in Photo Preview -- Fixed issue with Info side block - missing markup -- Fixed issue with Upload dialog layout with some resolutions/fonts -- ADMIN: Added option to hide breadcrumbs -- ADMIN: Added prerequisite check for Info module - required for Thumb meta data display - -version 2.1.7 -- Added support for missing images in the thumbs to allow proper operations with empty albums or albums with broken thumbs -- Some color optimizations -- Color improvements for "Add Image" dialog -- Better support for Basket module - -version 2.1.6 -- Wind colorpack adjusted to closer match default Wind theme - -version 2.1.5 -- Minor changes in ADMIN infrastructure -- ADMIN: added check for Kbd Navigation module -- ADMIN: New color pack - carbon - -version 2.1.4 -- Minor refactoring in paginator -- Added support for keyboard navigation module (http://codex.gallery2.org/Gallery3:Modules:kbd_nav) - -version 2.1.3 -- Sidebar restricted to item related pages (album, photo, movie, etc) -- Fixed issue with bottom border not applied to all instances of H1 tag -- Min footer size set to 4em -- ADMIN: "Photo: Description Display Mode" option added -- ADMIN: Added new maintenance operation - "Reset Exif Info" - -version 2.1.2 -- Fixed issue with Album thumbs - empty space under -- Thumb Item's Title Display Mode expanded to be applied to Item's description in Photo page -- More documentations in CSS files, some movements -- Some cleanup for Wind color pack -- Fixed font name typo in screen.css -- Fixed "Waiting" roller for Wind theme to match background -- Added "up" button in navigation - -version 2.1.1 -- Increased size of Add photo dialog for better display on some lower resolutions. -- ADMIN: New option: "Thumb: Item's Title Display Mode" - specifies how to display item's title in thumbs : Overlay Bottom Hide - -version 2.1.0 -- Custom Info Block to include item's description -- Image is centered when "Actual Size" aspect is used for thumbs -- Added support for color packs - included: greydragon, wind -- ADMIN: Improved error handling -- ADMIN: Disable submit button on click to prevent Dbl-click -- ADMIN: New option: Enable page cache - adds header marker for page to be cached for 60 seconds - -version 2.0.1 -- Enable BBCode/HTML support in individual photo descriptions -- Fixed main menu overlay issue when in top position -- Theme's credits moved into dedicated method -- CSS clean up -- Comments module layout enhancements - -version 2.0.0 -- Major redesign of the gallery flow. - - Added caption and metadata (Admin/optional) overlay for thumbs. - - Added description overlay in individual Photo view (look for "Learn More" marker). - - Based on Admin setting, thumbs are adjusted to fit Digital/Film/Actual size. -- Attempt to fix issue with JS load latency to prevent unhandled AJAX calls -- Added code protection for theme initialization procedure -- ADMIN: Thumb Aspect Ratio option. See help section for more info. - -version 1.8.2 -- Increased based font size -- Layout adjusted to match new settings -- ADMIN: New option - Place Login Link in the Header - -version 1.8.1 -- ADMIN: small adjustments in layout and help info -- 3rd party module's related CSS moved into contrib.css -- Adjust user profile screen to match new layout -- initial design for calendar module - -version 1.8.0 -- ADMIN: Major redesign of the layout. Help section added. -- ADMIN: New option - Show main menu for guest user -- Minimum required Gallery version set to 30 -- When configured not to use sidebar, theme is switched into 4 columns layout - -version 1.7.6 -- Organize module: CSS improvements -- Fixed issue with Chrome browser - -version 1.7.5 -- ADMIN: Added option to reset theme to default state -- CSS: some size adjustments for dialogs. Added minimum height for overlay to keep dialogs from shrinking. - -version 1.7.4 -- ADMIN: Theme Gallery 3 core requirement changed to v.26 -- ADMIN: Most of theme's settings are documented using element's title attribute - hover over to see a description -- Edit Permissions form redesigned and enlarged to fit more information - -version 1.7.3 -- ADMIN: Default states for the theme options are no longer being stored. Please save theme settings at least once to take advantage of a new functionality. -- Photo Navigator default position is set to Top Only - -version 1.7.2 -- Fix in Uploader dialog to keep items inside respected boxes -- Organize module support has been abandoned. Please use GWT Organize module instead. Added item in Prerequisites Checklist. - -version 1.7.1 -- CSS: Fixed visibility of the "Select Photo" button in "Add photo" dialog -- CSS: Fixed "ghost" line for navigation buttons when zoomed-in in IE -- Admin: fixed issue with prerequisite check not detecting deleted modules -- /views/support folder deprecated. Logic moved into Theme_View extension class for Theme_View_Core -- Theme Options Page management, generic Page code and BBCode processor moved into Theme_View class -- HACK: Info block is not displayed if there is no description for the item - -version 1.6.4 -- Admin: Added "Show Sidebar for Albums only" option -- Admin: added error visibility to the requirements validation list -- Small CSS adjustments: Fixed footer min size issue when no site credit info is displayed; added space between Credits in the footer and Footer text area. -- Few missing parts from last git sync - -version 1.6.3 -- Kohana 2.4 support -- Support for Movie files view -- Admin: Allow hide Sidebar Block header - -version 1.6.2 -- Admin: Page navigator option changed to use combobox -- Admin: Added option to hide item description in albums - -version 1.6.2 -- Small CSS adjustments. -- All operation dialogs should be visible now -- Context menu: "Rotate 90..." items are removed due to an issue with image quality affected by the operation -- Context menu: "Choose as the album cover" is now properly handled - -version 1.6.1 -- Admin: When allowed sidebar position is "Default Only", don't disregard selected Default position -- Adjust item's toolbar buttons to align properly when side bar position is fixed -- BBCode parser improved to support stripping of BBCode for Page title and breadcrumbs -- Fixed issue with main menu missing class declaration not allowing open dialogs -- Adjust context dialogs to properly show caption info -- Caption added to Full size Preview -- "New Comment" form styled -- Admin: Option to align main menu to the top and Breadcrumbs to the left - -version 1.6.0 -- Admin: Fixed issue with "Rebuild thumbs" option in theme admin -- Admin: Fixed issue with Item's toolbar not properly aligned in Quirks Mode -- Exif data dialog Layout changes -- Item context menu improvements: - - Fixed issue with submit logic - - Layout fixes for context menu dialogs - -version 1.5.8 -- Admin: First release of the Theme admin option. After theme installation, visit Appearance/Theme - Options to configure the theme. If you had older version of the theme, initial setup is also required. - The following settings are available: - - Rows per album page - theme uses 3 columns layout for pictures, therefore default page_size is computed in x3 increments - - Thumb size is restricted to 200 and therefore not available for administration - - Mark to build resizes/thumbs - allows force rebuilding of images - - Show/Hide top/bottom photo navigators - - Specify allowed and default sidebar position - - Administrator can now specify Copyright message to display in the footer - - Site logo is now default to Gallery 3 logo, but admin can provide a path to custom logo. - - Admin module validates Theme's requirements (Shadowbox module need to be installed/active) -- Sidebar session cookie is set to expire in 365 days - -version 1.5.7 -- Status message has been moved into header as popup to prevent obstruction of the main view. - jQuery is used to fade it out in 10 sec. -- Improved logic for dialogs on submit -- Theme related JS has been moved out of the page.html.php - -version 1.5.6 -- Fixed issue with tollbar buttons not properly aligned/shown when page is resized. -- Copyright info moved into DB. To change default settings add [th_greydragon/copyright] into VARS table. - -version 1.5.5 -- CSS fixes. -- Theme adjusted to be compatible with latest Git. -- Login links are moved into footer. -- Pagination module redesigned to support new structure of paging data. - -version 1.5.4 -- CSS fixes. -- Added support for Comments block. -- Improved support for Modal dialogs. - -version 1.5.3 -- Updated to match latest git. -- Exif menu customization is now part of the theme. -- Sidebar management button is disabled for current mode. - -version 1.5.2 -- Code, layout, css cleanup. -- New thumbs for buttons. -- First set of Ajax dialogs is ready and now operational: Login, user info, edit album, exit info. -- Fixed some browser related issues. \ No newline at end of file diff --git a/3.0/themes/greydragon/controllers/greydragon.php b/3.0/themes/greydragon/controllers/greydragon.php deleted file mode 100644 index 0796d801..00000000 --- a/3.0/themes/greydragon/controllers/greydragon.php +++ /dev/null @@ -1,39 +0,0 @@ -page_title = t("%name Profile", array("name" => $user->display_name())); - $v->content = new View("user_profile.html"); - - $v->content->user = $user; - $v->content->contactable = - !$user->guest && $user->id != identity::active_user()->id && $user->email; - $v->content->editable = - identity::is_writable() && !$user->guest && $user->id == identity::active_user()->id; - - $event_data = (object)array("user" => $user, "content" => array()); - module::event("show_user_profile", $event_data); - $v->content->info_parts = $event_data->content; - - print $v; - } -*/ -} diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/colors.css b/3.0/themes/greydragon/css/colorpacks/carbon/colors.css deleted file mode 100644 index 57fd30dd..00000000 --- a/3.0/themes/greydragon/css/colorpacks/carbon/colors.css +++ /dev/null @@ -1,192 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * ColorPack: Carbon - Default color pack - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* styles.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -html { background-color: #333; } -body { color: #999; background-color: #333; } - -h1 { border-bottom: #6f6f6f 1px solid; } -a { color: #999 !important; font-weight: bold; } -.ui-icon { background-image: url(images/ui-icons.png); } - -/* styles.css - Header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-header .g-message-block { border: 1px #888 solid; background-color: #AAA; color: #000; } -.g-breadcrumbs li { background: transparent url(images/ico-separator.png) no-repeat 0 0.2em; } - -/* styles.css - Content ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-main { background-color: #3f3f3f; margin-left: 10px; margin-right: 10px; } - -/* styles.css - Footer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -/* styles.css - Album Layout ~~~~~~~~~~~~~~~~~~~~~~~~~*/ -#g-info .g-description { border: #6f6f6f 1px solid; } - -.g-thumbslide, .g-thumbslide-ext { border: 1px solid #303E43; background-color: #555; } -.g-thumbcrop { border: 1px solid #303E43; } - -.g-album .g-thumbslide, -.g-album .g-thumbslide-ext { border-top: 1px solid #6f6f6f; border-left: 1px solid #6f6f6f; border-right: 4px double #6f6f6f; border-bottom: 4px double #6f6f6f; } -.g-photo .g-thumbslide, /* Need to compensate for double border in album's thumbs */ -.g-photo .g-thumbslide-ext { margin-bottom: 3px; } - -.g-thumbslide:hover .g-description { color: #fff; border-bottom: 1px solid #999; background: #1E1E1E; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } -.g-album .g-thumbslide:hover .g-description, -.g-album .g-thumbslide-ext .g-description { background: #555 url(images/ico-album.png) no-repeat 4px 2px; } - -.g-thumbslide:hover .g-metadata, -.g-thumbslide-ext:hover .g-metadata { border-top: 1px solid #999; background: #1E1E1E; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } - -/* styles.css - Photo Layout ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -div.g-resize { border: 1px solid #888; background: #555; } - -div.g-resize:hover .g-description { color: #fff; background: #1E1E1E; border-bottom: 1px solid #999; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } -div.g-resize .g-more { border: 1px solid #999; background: #1E1E1E; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } - -.g-movie { border: 1px solid #888; padding: 5px; background: #555; } - -/* styles.css - Reauthentificate ~~~~~~~~~~~~~~~~~~~~~*/ - -#g-reauthenticate-form ul { border: 1px #888 solid; } - -/* styles.css - Sidebar Blocks ~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-toolbar { border-bottom: 1px solid #737373; } - -/* styles.css - Sidebar Blocks : Common ~~~~~~~~~~~~~~*/ - -.g-block { border: 1px solid #737373; } -.g-block h2 { background: url(images/section.png) repeat-x; } - -/* styles.css - Sidebar Blocks : Buttons ~~~~~~~~~~~~~*/ - -#g-viewformat .g-viewthumb-left { background: url('images/view-left.png') no-repeat left top; } -#g-viewformat .g-viewthumb-right { background: url('images/view-right.png') no-repeat left top; } -#g-viewformat .g-viewthumb-full { background: url('images/view-full.png') no-repeat left top; } - -#g-slideshow-link { background: url("images/view-slideshow.png") top left no-repeat; } -.g-fullsize-link { background: url("images/view-fullsize.png") top left no-repeat; } -#g-exifdata-link { background: url("images/view-info.png") top left no-repeat; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* menus.css ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-site-menu ul { border: #000000 0 solid; } -#g-site-menu li a:hover { color: #000000; background-color: #333; } -#g-site-menu li:hover, -#g-site-menu li.iemhover { border: #303030 1px solid; background-color: #333; border-bottom: #000000 1px solid; } -#g-site-menu li ul { border: #000000 1px solid; } -#g-site-menu li ul li { border: #C0C0C0 0px solid; background-color: #333; } -#g-site-menu li ul li:hover, -#g-site-menu li ul li.iemhover { border: #C0C0C0 0 solid; background-color: #ddf2ff; } - -.g-item .g-context-menu { background-image: url(images/ui-icons.png); } -.g-item .g-context-menu:hover { background: #333 none; border: 1px #888 solid; } -.g-item .g-context-menu li li a:hover { background-color: #ddf2ff; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* forms.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-body { background: #101415 url('images/ajax-loading.gif') no-repeat center center; } -#sb-title { border-left: #303030 1px solid; border-right: #303030 1px solid; background-color: #333; } - -#sb-content.html_ajax p.g-error { color: red; } -#sb-content.html_ajax form { background-color: #101415; } -#sb-content.html_ajax>div { background-color: #101415; } - -/* forms.css - Permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-permissions .g-breadcrumbs { border: #303030 1px solid; } -#sb-content #g-edit-permissions-form { border: #303030 1px solid; } -#sb-content #g-move>ul { border: #303030 1px solid; } - -/* forms.css - Add item ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-add-photos-form .g-breadcrumbs { border: #303030 1px solid; } - -#g-add-photos-canvas { background-color: #101010; border: #303030 1px solid; } -#g-add-photos-button { border: #303030 1px solid; color: #bbb; } -#g-add-photos-status { background-color: #101010; border: #303030 1px solid; } - -#g-add-photos-status li.g-success { background: #d9efc2 url('images/ico-success.png') no-repeat .4em 50%; } -#g-add-photos-status li.g-error { background: #f6cbca url('images/ico-error.png') no-repeat .4em 50%; color: #f00; } - -/* forms.css - Organize ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content.html_ajax #g-organize { border: #303030 1px solid; } - -#g-organize-detail { border-left: #303030 1px solid; } -#g-organize .g-message-block { border-bottom: #303030 1px solid; } -.g-organize-microthumb-grid-cell { background-color: #303030; } -.g-organize-microthumb { background-color: #707070; } -#g-organize-controls { border-top: #303030 1px solid; } - -/* forms.css - User Profile ~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-user-profile .g-avatar { border: 1px solid #888; background: #555; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* menus.css ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-site-menu ul { border: #000000 0 solid; } -#g-site-menu li a:hover { color: #000000; background-color: #303030; } -#g-site-menu li:hover, -#g-site-menu li.iemhover { border: #303030 1px solid; background-color: #303030; border-bottom: #000000 1px solid; } -#g-site-menu li ul { border: #000000 1px solid; } -#g-site-menu li ul li { border: #C0C0C0 0px solid; background-color: #212121; } -#g-site-menu li ul li:hover, -#g-site-menu li ul li.iemhover { border: #C0C0C0 0 solid; background-color: #303030; } - -.g-item .g-context-menu { background-image: url(images/ui-icons.png); } -.g-item .g-context-menu:hover { background: #181818 none; border: 1px #888 solid; } -.g-item .g-context-menu li li a:hover { background-color: #303030; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* modules.css - Exif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-exif-data table { border: #303030 1px solid; } -#sb-content #g-exif-data .g-even { background-color: #404040; } -#sb-content #g-exif-data .g-odd { background-color: #303030; } - -/* modules.css - Info module ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-metadata .g-description { border-top: 1px solid #737373; } - -/* modules.css - Image block ~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-image-block img { border: 1px solid #888; background: #555; } - -/* modules.css - Comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-comments .g-author { border-bottom: 1px solid #202628; color: #999; } -#g-comments-link { background-image: url(images/view-comments.png); } -#g-comment-detail>ul>li { border: 1px dotted #737373; } -#g-comment-form { border: 1px dotted #737373; } - -/* modules.css - Calendar ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-view-menu #g-calendarview-link { background-image: url(images/view-calendar.png); } -#g-view-calendar-form ul { border: 1px #888 solid; } -table.calendar { border: #a2adbc 1px solid; color: #616b76; } -table.calendar th { border-bottom: #a2adbc 1px solid; border-right: #a2adbc 1px solid; background: #d9e2e1; color: #616b76; } -table.calendar td { border-bottom: #a2adbc 1px solid; border-right: #a2adbc 1px solid; } -table.calendar td.title { background-color: #a2adbc; color: #fff; } -table.calendar td.title a { color: #fff !important; } -table.calendar td a { color: red !important; } - -/* modules.css - Search ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-quick-search-form input[type="text"] { background-color: transparent; border: 1px solid #737373; color: #BBB; } -#g-quick-search-form input[type="submit"] { background: transparent url(images/search.png) no-repeat center top; border: none; } - -/* modules.css - Basket ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#checkout legend { background: url(images/section.png) repeat-x; } \ No newline at end of file diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/ajax-loading.gif b/3.0/themes/greydragon/css/colorpacks/carbon/images/ajax-loading.gif deleted file mode 100644 index 0996045a..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/ajax-loading.gif and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/ico-album.png b/3.0/themes/greydragon/css/colorpacks/carbon/images/ico-album.png deleted file mode 100644 index ac87ec4f..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/ico-album.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/ico-separator.png b/3.0/themes/greydragon/css/colorpacks/carbon/images/ico-separator.png deleted file mode 100644 index 3e158515..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/ico-separator.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/search.png b/3.0/themes/greydragon/css/colorpacks/carbon/images/search.png deleted file mode 100644 index 2d115cc8..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/search.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/section.png b/3.0/themes/greydragon/css/colorpacks/carbon/images/section.png deleted file mode 100644 index 8180ecb3..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/section.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/ui-icons.png b/3.0/themes/greydragon/css/colorpacks/carbon/images/ui-icons.png deleted file mode 100644 index 7d1723bf..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/ui-icons.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-calendar.png b/3.0/themes/greydragon/css/colorpacks/carbon/images/view-calendar.png deleted file mode 100644 index 5442fa51..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-calendar.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-comments.png b/3.0/themes/greydragon/css/colorpacks/carbon/images/view-comments.png deleted file mode 100644 index 5449126b..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-comments.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-full.png b/3.0/themes/greydragon/css/colorpacks/carbon/images/view-full.png deleted file mode 100644 index 7145fd9d..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-full.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-fullsize.png b/3.0/themes/greydragon/css/colorpacks/carbon/images/view-fullsize.png deleted file mode 100644 index ebd04237..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-fullsize.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-info.png b/3.0/themes/greydragon/css/colorpacks/carbon/images/view-info.png deleted file mode 100644 index ff30501c..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-info.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-left.png b/3.0/themes/greydragon/css/colorpacks/carbon/images/view-left.png deleted file mode 100644 index c59af5d0..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-left.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-right.png b/3.0/themes/greydragon/css/colorpacks/carbon/images/view-right.png deleted file mode 100644 index 59505456..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-right.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-slideshow.png b/3.0/themes/greydragon/css/colorpacks/carbon/images/view-slideshow.png deleted file mode 100644 index 2fb53ad0..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/carbon/images/view-slideshow.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/colors.css b/3.0/themes/greydragon/css/colorpacks/greydragon/colors.css deleted file mode 100644 index 22a6d40e..00000000 --- a/3.0/themes/greydragon/css/colorpacks/greydragon/colors.css +++ /dev/null @@ -1,178 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * ColorPack: GreyDragon - Default color pack - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* styles.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -html { background-color: #1A2022; } -body { color: #BBB; background: url(images/background.gif) #1A2022 repeat-x; } - -h1 { border-bottom: #737373 1px solid; } -a { color: #6392CF !important; } -.ui-icon { background-image: url(images/ui-icons.png); } - -/* styles.css - Header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-header .g-message-block { border: 1px #888 solid; background-color: #AAA; color: #000; } -.g-breadcrumbs li { background: transparent url(images/ico-separator.png) no-repeat 0 0.2em; } - -/* styles.css - Footer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-footer { background: url(images/footer.png) #1A2022 repeat-x top !important; } - -/* styles.css - Album Layout ~~~~~~~~~~~~~~~~~~~~~~~~~*/ -#g-info .g-description { border: #737373 1px solid; } - -.g-thumbslide, .g-thumbslide-ext { border: 1px solid #303E43; background: #1E1E1E url('images/image-thumb.gif') repeat-x; } -.g-thumbcrop { border: 1px solid #303E43; } - -.g-album .g-thumbslide, -.g-album .g-thumbslide-ext { border-top: 1px solid #43565B; border-left: 1px solid #43565B; border-right: 4px double #43565B; border-bottom: 4px double #43565B; } -.g-photo .g-thumbslide, /* Need to compensate for double border in album's thumbs */ -.g-photo .g-thumbslide-ext { margin-bottom: 3px; } - -.g-thumbslide:hover .g-description { color: #fff; border-bottom: 1px solid #999; background: #1E1E1E; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } -.g-album .g-thumbslide:hover .g-description, -.g-album .g-thumbslide-ext .g-description { background: #1E1E1E url(images/ico-album.png) no-repeat 4px 2px; } - -.g-thumbslide:hover .g-metadata, -.g-thumbslide-ext:hover .g-metadata { border-top: 1px solid #999; background: #1E1E1E; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } - -/* styles.css - Photo Layout ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -div.g-resize { border: 1px solid #888; background: #555; } - -div.g-resize:hover .g-description { color: #fff; background: #1E1E1E; border-bottom: 1px solid #999; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } -div.g-resize .g-more { border: 1px solid #999; background: #1E1E1E; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } - -.g-movie { border: 1px solid #888; padding: 5px; background: #555; } - -/* styles.css - Reauthentificate ~~~~~~~~~~~~~~~~~~~~~*/ - -#g-reauthenticate-form ul { border: 1px #888 solid; } - -/* styles.css - Sidebar Blocks ~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-toolbar { border-bottom: 1px solid #737373; } - -/* styles.css - Sidebar Blocks : Common ~~~~~~~~~~~~~~*/ - -.g-block { border: 1px solid #737373; background-color: #101415; } -.g-block h2 { background: url(images/section.png) repeat-x; } - -/* styles.css - Sidebar Blocks : Buttons ~~~~~~~~~~~~~*/ - -#g-viewformat .g-viewthumb-left { background: url('images/view-left.png') no-repeat left top; } -#g-viewformat .g-viewthumb-right { background: url('images/view-right.png') no-repeat left top; } -#g-viewformat .g-viewthumb-full { background: url('images/view-full.png') no-repeat left top; } - -#g-slideshow-link { background: url("images/view-slideshow.png") top left no-repeat; } -.g-fullsize-link { background: url("images/view-fullsize.png") top left no-repeat; } -#g-exifdata-link { background: url("images/view-info.png") top left no-repeat; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* forms.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-body { background: #101415 url('images/ajax-loading.gif') no-repeat center center; } -#sb-title { border-left: #303030 1px solid; border-right: #303030 1px solid; background: #101415 url('images/section.png') repeat-x; } - -#sb-content.html_ajax p.g-error { color: red; } -#sb-content.html_ajax form { background-color: #101415; } -#sb-content.html_ajax>div { background-color: #101415; } - -/* styles.css - Photo Slideshow ~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-counter a { color: #fff !important; font-weight: bold; font-size: 11px; } - -/* forms.css - Permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-permissions .g-breadcrumbs { border: #303030 1px solid; } -#sb-content #g-edit-permissions-form { border: #303030 1px solid; } -#sb-content #g-move>ul { border: #303030 1px solid; } - -/* forms.css - Add item ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-add-photos-form .g-breadcrumbs { border: #303030 1px solid; } - -#g-add-photos-canvas { background-color: #101010; border: #303030 1px solid; } -#ag-add-photos-button { border: #303030 1px solid; color: #bbb; } -#g-add-photos-status { background-color: #101010; border: #303030 1px solid; } - -#g-add-photos-status li.g-success { background: url('images/ico-success.png') transparent no-repeat .4em 50%; } -#g-add-photos-status li.g-error { background: url('images/ico-error.png') transparent no-repeat .4em 50%; color: #f00; } - -/* forms.css - Organize ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content.html_ajax #g-organize { border: #303030 1px solid; } - -#g-organize-detail { border-left: #303030 1px solid; } -#g-organize .g-message-block { border-bottom: #303030 1px solid; } -.g-organize-microthumb-grid-cell { background-color: #303030; } -.g-organize-microthumb { background-color: #707070; } -#g-organize-controls { border-top: #303030 1px solid; } - -/* forms.css - User Profile ~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-user-profile .g-avatar { border: 1px solid #888; background: #555; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* menus.css ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-site-menu ul { border: #000000 0 solid; } -#g-site-menu li a:hover { color: #000000; background-color: #303030; } -#g-site-menu li:hover, -#g-site-menu li.iemhover { border: #303030 1px solid; background-color: #303030; border-bottom: #000000 1px solid; } -#g-site-menu li ul { border: #000000 1px solid; } -#g-site-menu li ul li { border: #C0C0C0 0px solid; background-color: #212121; } -#g-site-menu li ul li:hover, -#g-site-menu li ul li.iemhover { border: #C0C0C0 0 solid; background-color: #303030; } - -.g-item .g-context-menu { background-image: url(images/ui-icons.png); } -.g-item .g-context-menu:hover { background: #181818 none; border: 1px #888 solid; } -.g-item .g-context-menu li li a:hover { background-color: #303030; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* modules.css - Exif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-exif-data table { border: #303030 1px solid; } -#sb-content #g-exif-data .g-even { background-color: #404040; } -#sb-content #g-exif-data .g-odd { background-color: #303030; } - -/* modules.css - Info module ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-metadata .g-description { border-top: 1px solid #737373; } - -/* modules.css - Image block ~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-image-block img { border: 1px solid #888; background: #555; } - -/* modules.css - Comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-comments .g-author { border-bottom: 1px solid #202628; color: #999; } -#g-comments-link { background-image: url(images/view-comments.png); } -#g-comment-detail>ul>li { border: 1px dotted #737373; } -#g-comment-form { border: 1px dotted #737373; } - -/* modules.css - Calendar ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-view-menu #g-calendarview-link { background-image: url(images/view-calendar.png); } -#g-view-calendar-form ul { border: 1px #888 solid; } -table.calendar { border: #a2adbc 1px solid; color: #616b76; } -table.calendar th { border-bottom: #a2adbc 1px solid; border-right: #a2adbc 1px solid; background: #d9e2e1; color: #616b76; } -table.calendar td { border-bottom: #a2adbc 1px solid; border-right: #a2adbc 1px solid; } -table.calendar td.title { background-color: #a2adbc; color: #fff; } -table.calendar td.title a { color: #fff !important; } -table.calendar td a { color: red !important; } - -/* modules.css - Search ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-quick-search-form input[type="text"] { background-color: transparent; border: 1px solid #737373; color: #BBB; } -#g-quick-search-form input[type="submit"] { background: transparent url(images/search.png) no-repeat center top; border: none; } - -/* modules.css - Basket ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#checkout legend { background: url(images/section.png) repeat-x; } diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/ajax-loading.gif b/3.0/themes/greydragon/css/colorpacks/greydragon/images/ajax-loading.gif deleted file mode 100644 index 0996045a..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/ajax-loading.gif and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/background.gif b/3.0/themes/greydragon/css/colorpacks/greydragon/images/background.gif deleted file mode 100644 index b8083564..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/background.gif and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/footer.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/footer.png deleted file mode 100644 index 04d5ee54..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/footer.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/ico-album.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/ico-album.png deleted file mode 100644 index ac87ec4f..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/ico-album.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/ico-error.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/ico-error.png deleted file mode 100644 index c37bd062..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/ico-error.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/ico-separator.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/ico-separator.png deleted file mode 100644 index 3e158515..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/ico-separator.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/ico-success.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/ico-success.png deleted file mode 100644 index a9925a06..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/ico-success.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/image-thumb.gif b/3.0/themes/greydragon/css/colorpacks/greydragon/images/image-thumb.gif deleted file mode 100644 index bc3a192f..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/image-thumb.gif and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/search.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/search.png deleted file mode 100644 index 1bfa4115..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/search.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/section.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/section.png deleted file mode 100644 index 8180ecb3..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/section.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/ui-icons.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/ui-icons.png deleted file mode 100644 index 7ab15cae..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/ui-icons.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-calendar.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-calendar.png deleted file mode 100644 index 206ccd66..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-calendar.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-comments.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-comments.png deleted file mode 100644 index 293c587e..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-comments.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-full.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-full.png deleted file mode 100644 index b75de946..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-full.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-fullsize.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-fullsize.png deleted file mode 100644 index ed76257a..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-fullsize.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-info.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-info.png deleted file mode 100644 index 521439ce..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-info.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-left.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-left.png deleted file mode 100644 index b5b93c7a..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-left.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-right.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-right.png deleted file mode 100644 index a400c638..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-right.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-slideshow.png b/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-slideshow.png deleted file mode 100644 index c6a471ac..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/greydragon/images/view-slideshow.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/colors.css b/3.0/themes/greydragon/css/colorpacks/wind/colors.css deleted file mode 100644 index 09ab5a6a..00000000 --- a/3.0/themes/greydragon/css/colorpacks/wind/colors.css +++ /dev/null @@ -1,184 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * ColorPack: Wind - Wind theme-like color pack - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* styles.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -html { background-color: #ccc; } -body { color: #000; background-color: #ccc; padding-left: 10px; padding-right: 10px; } - -a { color: #33629f !important } -.ui-icon { background-image: url(images/ui-icons.png); } - -/* styles.css - Header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-header { background-color: #e8e8e8; border-bottom: #ccc 1px solid; } -#g-header .g-message-block { border: 1px #888 solid; background-color: #aaa; color: #000; } -.g-breadcrumbs li { background: transparent url(images/ico-separator.png) no-repeat 0 0.2em; } - -/* styles.css - Main ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-main { background-color: #fff; } - -/* styles.css - Footer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-footer { background-color: #e8e8e8; border-top: #ccc 1px solid; } - -/* styles.css - Album Layout ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-info h1, #g-album-header h1 { border-bottom: #ccc 1px solid; } -#g-info .g-description { border: #888 1px solid; } - -.g-thumbslide { border: 1px solid #707E83; background-color: #e8e8e8; } -.g-thumbcrop { border: 1px solid #707E83; } - -.g-album .g-thumbslide, -.g-album .g-thumbslide-ext { border-top: 1px solid #707E83; border-left: 1px solid #707E83; border-right: 4px double #707E83; border-bottom: 4px double #707E83; } -.g-photo .g-thumbslide, /* Need to compensate for double border in album's thumbs */ -.g-photo .g-thumbslide-ext { margin-bottom: 3px; } - -.g-thumbslide:hover .g-description { color: #000; border-bottom: 1px solid #999; background: #e8e8e8; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } -.g-album .g-thumbslide:hover .g-description, -.g-album .g-thumbslide-ext .g-description { background: #fff url(images/ico-album.png) no-repeat 4px 2px; } - -.g-thumbslide:hover .g-metadata, -.g-thumbslide-ext:hover .g-metadata { border-top: 1px solid #999; background: #e8e8e8; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } - -/* styles.css - Photo Layout ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -div.g-resize { border: 1px solid #888; background: #e8e8e8; } - -div.g-resize:hover .g-description { color: #000; background: #e8e8e8; border-bottom: 1px solid #999; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } -div.g-resize .g-more { border: 1px solid #999; background: #e8e8e8; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } - -.g-movie { border: 1px solid #888; padding: 5px; background: #e8e8e8; } - -/* styles.css - Reauthentificate ~~~~~~~~~~~~~~~~~~~~~*/ - -#g-reauthenticate-form ul { border: 1px #888 solid; } - -/* styles.css - Sidebar Blocks ~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-toolbar { border-bottom: 1px solid #ccc; } - -/* styles.css - Sidebar Blocks : Common ~~~~~~~~~~~~~~*/ - -.g-block { border: 1px solid #ccc; } -.g-block h2 { background-color: #e8e8e8; } - -/* styles.css - Sidebar Blocks : Buttons ~~~~~~~~~~~~~*/ - -#g-viewformat .g-viewthumb-left { background: url('images/view-left.png') no-repeat left top; } -#g-viewformat .g-viewthumb-right { background: url('images/view-right.png') no-repeat left top; } -#g-viewformat .g-viewthumb-full { background: url('images/view-full.png') no-repeat left top; } - -#g-slideshow-link { background: url("images/view-slideshow.png") top left no-repeat; } -.g-fullsize-link { background: url("images/view-fullsize.png") top left no-repeat; } -#g-exifdata-link { background: url("images/view-info.png") top left no-repeat; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* forms.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-body { background: #fff url('images/ajax-loading.gif') no-repeat center center; } -#sb-title { border-left: #303030 1px solid; border-right: #303030 1px solid; background: #e8e8e8; color: #000; } -#sb-title-inner { color: #000; } - -#sb-content.html_ajax p.g-error { color: red; } -#sb-content.html_ajax form { background-color: #fff; } -#sb-content.html_ajax>div { background-color: #fff; } - -/* forms.css - Permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-permissions .g-breadcrumbs { border: #303030 1px solid; } -#sb-content #g-edit-permissions-form { border: #303030 1px solid; } -#sb-content #g-move>ul { border: #303030 1px solid; } - -/* forms.css - Add item ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-add-photos-form .g-breadcrumbs { border: #303030 1px solid; } - -#g-add-photos-canvas { background-color: #fff; border: #303030 1px solid; } -#g-add-photos-button { border: #303030 1px solid; } -#g-add-photos-status { background-color: #fff; border: #303030 1px solid; } - -#g-add-photos-status li.g-success { background: #d9efc2 url('images/ico-success.png') no-repeat .4em 50%; } -#g-add-photos-status li.g-error { background: #f6cbca url('images/ico-error.png') no-repeat .4em 50%; color: #f00; } - -/* forms.css - Organize ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content.html_ajax #g-organize { border: #303030 1px solid; } - -#g-organize-detail { border-left: #303030 1px solid; } -#g-organize .g-message-block { border-bottom: #303030 1px solid; } -.g-organize-microthumb-grid-cell { background-color: #fff; } -.g-organize-microthumb { background-color: #fff; } -#g-organize-controls { border-top: #303030 1px solid; } - -/* forms.css - User Profile ~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-user-profile h1 { border-bottom: #ccc 1px solid; } -#g-user-profile .g-avatar { border: 1px solid #888; background: #fff; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* menus.css ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-site-menu ul { border: #000000 0 solid; } -#g-site-menu li { background-color: #bdd2ff; } -#g-site-menu li a:hover { color: #000000; background-color: #cfdeff; } -#g-site-menu li:hover, -#g-site-menu li.iemhover { border: #303030 1px solid; background-color: #cfdeff; border-bottom: #cfdeff 1px solid; } -#g-site-menu li ul { border: #cfdeff 1px solid; } -#g-site-menu li ul li { border: #C0C0C0 0px solid; background-color: #bdd2ff; } -#g-site-menu li ul li:hover, -#g-site-menu li ul li.iemhover { border: #C0C0C0 0 solid; background-color: #ddf2ff; } - -.g-item .g-context-menu { background-image: url(images/ui-icons.png); } -.g-item .g-context-menu:hover { background: #bdd2ff none; border: 1px #888 solid; } -.g-item .g-context-menu li li a:hover { background-color: #ddf2ff; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* modules.css - Exif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-exif-data table { border: #303030 1px solid; } -#sb-content #g-exif-data .g-even { background-color: #A0A0A0; } -#sb-content #g-exif-data .g-odd { background-color: #C0C0C0; } - -/* modules.css - Info module ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-metadata .g-description { border-top: 1px solid #ccc; } - -/* modules.css - Image block ~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-image-block img { border: 1px solid #888; background: #555; } - -/* modules.css - Comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-comments .g-author { border-bottom: 1px solid #202628; color: #999; } -#g-comments-link { background-image: url(images/view-comments.png); } -#g-comment-detail>ul>li { border: 1px dotted #ccc; } -#g-comment-form { border: 1px dotted #ccc; } - -/* modules.css - Calendar ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-view-menu #g-calendarview-link { background-image: url(images/view-calendar.png); } -#g-view-calendar-form ul { border: 1px #888 solid; } -table.calendar { border: #a2adbc 1px solid; color: #616b76; } -table.calendar th { border-bottom: #a2adbc 1px solid; border-right: #a2adbc 1px solid; background: #d9e2e1; color: #616b76; } -table.calendar td { border-bottom: #a2adbc 1px solid; border-right: #a2adbc 1px solid; } -table.calendar td.title { background-color: #a2adbc; color: #fff; } -table.calendar td.title a { color: #fff !important; } -table.calendar td a { color: red !important; } - -/* modules.css - Search ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-quick-search-form input[type="text"] { background-color: transparent; border: 1px solid #ccc; color: #666; } -#g-quick-search-form input[type="submit"] { border: #c5dbec 1px solid; text-indent: 0; width: auto; height: auto; font: 80% arial, helvetica, clean, sans-serif; font-weight: bold; padding-top: 3px; padding-bottom: 3px; } -#g-search-results h1 { border-bottom: #ccc 1px solid; } - -/* modules.css - Basket ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#checkout legend { background-color: #e8e8e8; } \ No newline at end of file diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/ajax-loading.gif b/3.0/themes/greydragon/css/colorpacks/wind/images/ajax-loading.gif deleted file mode 100644 index 53dd589f..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/ajax-loading.gif and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/ico-album.png b/3.0/themes/greydragon/css/colorpacks/wind/images/ico-album.png deleted file mode 100644 index ac87ec4f..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/ico-album.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/ico-error.png b/3.0/themes/greydragon/css/colorpacks/wind/images/ico-error.png deleted file mode 100644 index c37bd062..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/ico-error.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/ico-separator.png b/3.0/themes/greydragon/css/colorpacks/wind/images/ico-separator.png deleted file mode 100644 index 3e158515..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/ico-separator.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/ico-success.png b/3.0/themes/greydragon/css/colorpacks/wind/images/ico-success.png deleted file mode 100644 index a9925a06..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/ico-success.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/ui-icons.png b/3.0/themes/greydragon/css/colorpacks/wind/images/ui-icons.png deleted file mode 100644 index a8bd54b5..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/ui-icons.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/view-calendar.png b/3.0/themes/greydragon/css/colorpacks/wind/images/view-calendar.png deleted file mode 100644 index 13e0e8fa..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/view-calendar.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/view-comments.png b/3.0/themes/greydragon/css/colorpacks/wind/images/view-comments.png deleted file mode 100644 index f33bdf19..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/view-comments.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/view-full.png b/3.0/themes/greydragon/css/colorpacks/wind/images/view-full.png deleted file mode 100644 index e465d366..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/view-full.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/view-fullsize.png b/3.0/themes/greydragon/css/colorpacks/wind/images/view-fullsize.png deleted file mode 100644 index 58b3e0b4..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/view-fullsize.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/view-info.png b/3.0/themes/greydragon/css/colorpacks/wind/images/view-info.png deleted file mode 100644 index 2cc7a68e..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/view-info.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/view-left.png b/3.0/themes/greydragon/css/colorpacks/wind/images/view-left.png deleted file mode 100644 index b51e3368..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/view-left.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/view-right.png b/3.0/themes/greydragon/css/colorpacks/wind/images/view-right.png deleted file mode 100644 index bd72adfc..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/view-right.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/colorpacks/wind/images/view-slideshow.png b/3.0/themes/greydragon/css/colorpacks/wind/images/view-slideshow.png deleted file mode 100644 index 61bf18e1..00000000 Binary files a/3.0/themes/greydragon/css/colorpacks/wind/images/view-slideshow.png and /dev/null differ diff --git a/3.0/themes/greydragon/css/forms.css b/3.0/themes/greydragon/css/forms.css deleted file mode 100644 index ab246779..00000000 --- a/3.0/themes/greydragon/css/forms.css +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * CSS rules related to forms/dialogs - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* forms.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -input[type="submit"], .g-button, button { cursor: pointer; /* hand-shaped cursor */ cursor: hand; /* for IE 5.x */ font-size: 0.8em; color: #333 !important; padding: 2px 10px; margin-top: 0.4em; border: 1px solid; border-color: #999 #666 #666 #999; background-color: #ddd; font-weight: normal; } - -#sb-content.html_ajax { padding: 0 0.8em; margin: 0; } -#sb-content.html_ajax p.g-error { padding-top: 0.4em; } - -#sb-content.html_ajax form { background-color: #101415; overflow: hidden; } -#sb-content.html_ajax form fieldset { border: none; } -#sb-content.html_ajax form legend { display: none; width: 100%; } -#sb-content.html_ajax form ul { padding: 0; } -#sb-content.html_ajax form li { padding-top: 0.2em; } -#sb-content.html_ajax form>fieldset>ul { margin: 0 2px; } -#sb-content.html_ajax form label { display: block; padding: 0.2em 0; } -#sb-content.html_ajax form textarea { width: 99%; height: 4em; } -#sb-content.html_ajax input[type="submit"]{ margin: 6px 0; } -#sb-content.html_ajax input[type="text"], -#sb-content.html_ajax input[type="password"] { width: 99%; } -#sb-content.html_ajax>div { height: 94%; padding-top: 0.2em; overflow: auto; } -#sb-content #g-text { min-height: 6em; } - -#sb-content fieldset fieldset { border: none; } -#sb-content fieldset fieldset li { float: left; display: inline; margin-right: 1em; } - -/* forms.css - Login ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-login-form { width: 100%; } -#sb-content #g-login form ul { min-height: 10em; } -#sb-content #g-password-reset { margin-left: 0.4em; } - -/* forms.css - Edit Permissions ~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-permissions fieldset { border: none; margin: 1px; overflow: auto; width: 100%; } -#sb-content #g-permissions .g-breadcrumbs { position: static; padding: 0.4em; font-size: small; margin: 0.4em 0; } -#sb-content #g-permissions .g-breadcrumbs .g-first { padding-left: 0; } - -#sb-content #g-edit-permissions-form { margin: 0.4px 0; } -#sb-content #g-edit-permissions-form>fieldset>legend { display: none; } -#sb-content #g-edit-permissions-form>fieldset>table { font-size: small; } -#sb-content #g-edit-permissions-form>fieldset>table th, -#sb-content #g-edit-permissions-form>fieldset>table td { padding: 1px 2px; } - -/* forms.css - Delete Item ~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-confirm-delete { height: 5em; padding: 0.8em 0 0 0; } - -/* forms.css - Move Item ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-move>ul { height: 290px; margin-bottom: 0.4em; padding: 10px; overflow: auto; } -#sb-content #g-move>form { background: none; } - -/* forms.css - Add photo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-add-photos-form { height: 96%; } -#sb-content #g-add-photos-form .g-breadcrumbs { position: static; margin: 4px 0 0 0; padding: 4px; font-size: x-small; } -#sb-content #g-add-photos-form .g-breadcrumbs li { padding-top: 0; } -#sb-content #g-add-photos-form .g-breadcrumbs .g-first { padding-left: 0; } - -#g-add-photos-canvas { margin-top: 4px; height: 100px; } -#g-add-photos-button { padding: 2px 8px; z-index: 10; zoom: 1; } -#g-uploadifyUploader { z-index: 1005; zoom: 1; } -#g-uploadifyQueue { overflow: auto; height: 100%; } -#g-add-photos-status { margin-top: 4px; height: 90px; overflow: auto; } -#g-add-photos-status #g-action-status { margin: 0 0 1px 0; width: 100%; } -#g-add-photos-status #g-action-status li { margin: 0 0 1px 0; padding: 2px 0; text-indent: 30px; width: 100%; } - -/* forms.css - Organize ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content.html_ajax #g-organize { height: 440px; } -#g-organize #g-organize-content-pane { display: block; height: 440px; width: 690px; margin: 0 !important; overflow: hidden; } -#g-organize #g-organize-content-pane>div { float: left; height: 440px; } -#g-organize #g-organize-content-pane #g-organize-tree-container { overflow: auto; width: 164px; height: 428px; padding: 0 2px 0 4px !important; } -#g-organize #g-organize-detail { width: 518px; } -#g-organize #g-organize-detail .g-message-block li { padding: 0; } -#g-organize #g-organize-tree-container>ul { font-size: x-small; } -#g-organize #g-organize-tree-container>ul ul { padding: 0px; } -#g-organize #g-organize-album-tree { padding: 0; } -#g-organize .g-message-block { padding: 4px 0 4px 10px; } -#g-organize-microthumb-panel { background-color: transparent; border: none; height: 360px; } -#g-organize-microthumb-grid { position: static; height: 360px; border-style: none; padding: 0 2px !important; } -.g-organize-microthumb-grid-cell { float: left; margin: 2px; } -.g-organize-microthumb-grid-cell .ui-icon-note { background-position: -194px -144px; left: 8px; bottom: 4px; } -#g-organize-controls { position: absolute; background-color: transparent; padding: 6px 10px; } -#g-organize-controls li { display: inline; } -.g-organize-album-text { border: transparent 1px solid; } -#g-organize-close { display: none; } - -/* forms.css - User Profile ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-user-profile h1 { padding-bottom: 1px; margin: 0 0; } -#g-user-profile>div { margin: 2em 0 1em 10em; } -#g-user-profile .g-block-content { text-align: left; } -#g-user-profile .g-avatar { float: left; padding: 2px; } - -#g-user-profile th { text-align: left; padding-right: 20px; } -#g-change-email-user-form { min-height: 200px; } -#g-edit-user-form ul { min-height: 200px; } - -#g-quick-search-form input[type="submit"] { filter: none; margin-top: 0; } \ No newline at end of file diff --git a/3.0/themes/greydragon/css/layout.css b/3.0/themes/greydragon/css/layout.css deleted file mode 100644 index db55e4af..00000000 --- a/3.0/themes/greydragon/css/layout.css +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * CSS rules related to general layout - * Defined as 70em wide - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* layout.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -html { overflow: auto; overflow: -moz-scrollbars-vertical; overflow-y: scroll; } -* { margin: 0px; } -body { min-width: 70em; padding: 0; margin: 0; } - -.g-hideitem { display: none; } - -/* layout.css - Header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-header { position: relative; min-width: 70em; z-index: 5; } - -/* layout.css - Main ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-main { min-width: 69.7em; height: auto; bottom: auto; } -#g-main-in { min-width: 69.7em; height: 100%; overflow: auto; bottom: auto; } -#g-column-left { float: left; width: 16em; min-height: 32em; overflow: hidden; height: 100%; } -#g-column-right { float: right; width: 16em; min-height: 32em; overflow: hidden; height: 100%; } -#g-column-center { margin: 0 17em 0 17em; min-height: 32em; overflow: hidden; height: 100%; } -#g-column-centerleft { margin: 0; min-height: 32em; overflow: hidden; height: 100%; } -#g-column-centerright { margin: 0; min-height: 32em; overflow: hidden; height: 100%; } -#g-column-centerfull { position: relative; margin: 0 0; min-height: 31em; overflow: hidden; height: 100%; } - -/* layout.css - Footer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-footer { position: relative; height: auto; min-width: 70em; min-height: 4em; clear: both; display: block; overflow: auto; } -#g-footer-leftside { float: left; display: inline; } -#g-footer-rightside { float: right; display: inline; } - diff --git a/3.0/themes/greydragon/css/menus.css b/3.0/themes/greydragon/css/menus.css deleted file mode 100644 index 3ba173f2..00000000 --- a/3.0/themes/greydragon/css/menus.css +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * CSS rules related to menus - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* menus.css - Main menu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-site-menu { position: absolute; left: 24em; } -#g-site-menu.default { bottom: 0; } -#g-site-menu.top { top: 0; } -#g-site-menu ul { float: left; padding-left: 0; width: 100%; white-space: nowrap; z-index: 10; } -#g-site-menu ul ul ul { padding-top: 0; } -#g-site-menu a { display: block; padding: 0.2em 0.4em; text-align: center; width: auto; letter-spacing: 0; cursor: pointer; } -#g-site-menu li { float: left; padding: 0; background-color: transparent; border: transparent 1px solid; z-index: 10; } -#g-site-menu li a:hover { cursor: pointer; } -#g-site-menu li ul a { text-align: left; padding: 0.3em 0; text-indent: 0.8em; letter-spacing: 0; cursor: pointer; } -#g-site-menu li ul a:hover { background-image: none; cursor: pointer; } -#g-site-menu li ul { position: absolute; margin: 0 0 0 -1px; width: 14em; height: auto; left: -999em; } - -#g-site-menu li li { width: 14em; padding-right: 0; } -#g-site-menu li ul a { width: 14em; } -#g-site-menu li ul ul { margin: -1.9em 0 0 14em; } -#g-site-menu li:hover ul ul, -#g-site-menu li:hover ul ul ul, -#g-site-menu li.iemhover ul ul, -#g-site-menu li.iemhover ul ul ul { left: -999em; } -#g-site-menu li:hover ul, -#g-site-menu li li:hover ul, -#g-site-menu li li li:hover ul, -#g-site-menu li.iemhover ul, -#g-site-menu li li.iemhover ul, -#g-site-menu li li li.iemhover ul { left: auto; } - -#g-site-menu>ul>li>ul { display: none; } - -#g-site-menu .ui-icon-rotate-ccw, -#g-site-menu .ui-icon-rotate-cw { display: none; } - -/* menus.css - Context menu ~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-item .g-context-menu { position: absolute; margin: 0; padding: 0; top: 6px; left: 196px; width: 14px; height: 14px; background-position: -178px -144px; z-index: 3; } -.g-item .g-context-menu li { width: 100%; padding: 0; margin: 0; text-indent: -9999px; } -.g-item .g-context-menu>li>a { font-size: 0em; } -.g-item .g-context-menu:hover { top: 4px; left: 6px; width: 200px; height: auto; z-index: 100; } -.g-item .g-context-menu ul { padding: 0; margin: 0; } -.g-item .g-context-menu li li { display: none; } -.g-item .g-context-menu li li a { display: block; padding: 4px 6px; } -.g-item .g-context-menu:hover li li { display: block; text-indent: 0px; } -.g-item .g-context-menu li li a.ui-icon-rotate-ccw, -.g-item .g-context-menu li li a.ui-icon-rotate-cw { display: none; } - -.g-item.g-detail .g-context-menu { left: auto; right: 6px; } -.g-item.g-detail .g-context-menu:hover { left: auto; right: 6px; } \ No newline at end of file diff --git a/3.0/themes/greydragon/css/modules.css b/3.0/themes/greydragon/css/modules.css deleted file mode 100644 index 371434f8..00000000 --- a/3.0/themes/greydragon/css/modules.css +++ /dev/null @@ -1,135 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * CSS rules related to modules - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* modules.css - ShadowBox Skin ~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-title { overflow: hidden; } -#sb-title-inner { font-size: 10pt; font-weight: bold; padding-left: 10px; } -#sb-nav #sb-nav-close { background-image: url('../images/close.png'); width: 60px; } -#sb-container > #sb-overlay { min-height: 530px; overflow: auto; } - -/* modules.css - Exif Data ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-exif-data { width: auto; background-image: none; } -#sb-content #g-exif-data table { width: 100%; } -#sb-content #g-exif-data td { padding: 0.4em; } - -/* modules.css - Image Block ~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-image-block>div { margin-left: 1px; margin-right: 1px; } -.g-image-block { text-align: center; } -.g-image-block img { padding: 5px; } - -/* modules.css - RSS Feeds ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -ul#g-feeds { padding: 0; margin: 0; } - -/* modules.css - Tags ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-tag-cloud ul { padding: 0; font-size: 100%; } -#g-tag-cloud ul li { line-height: 1.2em; } -#g-tag-cloud ul li span { display: none; } -#g-add-tag-form { display: none; } - -/* modules.css - Comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-comments { margin-top: 2em; padding-top: 0.4em; float: left; width: 100%; } -#g-comments ul li { margin: 0.4em 0; } -#g-comments .g-author { height: 32px; line-height: 32px; } -#g-comments .g-avatar { height: 32px; margin-right: .4em; width: 32px; } - -#g-admin-comment-button { width: 27px; right: 0.2em; text-indent: -900em; } -#g-comments-link { background-position: top left; background-repeat: no-repeat; } -#g-comments-link:hover { background-position: left bottom; } -#g-comment-detail ul { margin-top: 2em; padding: 0; } -#g-comment-detail>ul>li { margin: 4px 0; padding: 6px; min-height: 40px; } -#g-comment-detail div { margin-top: 6px; padding-bottom: 8px; } - -#g-comment-form fieldset { border: none; } -#g-comment-form legend { display: none; width: 100%; } -#g-comment-form ul { padding: 0; } -#g-comment-form>fieldset>ul { margin: 0px 10px; } -#g-comment-form label { display: block; } -#g-comment-form textarea { width: 99%; height: 140px; } -#g-comment-form input[type="text"], -#g-comment-form input[type="password"] { width: 99%; } - -/* modules.css - Gallery Stats ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-gallerystats ul { padding: 0; font-size: x-small; } - -/* modules.css - Info ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-metadata ul { padding: 0; } -#g-metadata .g-description { margin-top: 0.4em; padding: 0.4em 0; } - -/* modules.css - Calendar ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-calendarview-link:hover { background-position: left bottom; } - -#g-view-calendar-form fieldset { border: none; } -#g-view-calendar-form ul { padding: 8px; } -#g-view-calendar-form li { padding-top: 8px; display: inline; padding-left: 10px; } -#g-view-calendar-form label { margin: 4px 0; } -#g-view-calendar-form select { margin: 4px 10px; } - -table.calendar { border-spacing: 1px; } -table.calendar td.title a { font-weight: bold; } - -/* modules.css - ClustrMaps ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-clustrmaps .g-block-content { text-align: center; } - -/* modules.css - GPS Info ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-exif-gps-maps ul { padding-left: 0; } - -/* modules.css - Search ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-quick-search-form { position: absolute; top: 3em; right: 1em; background: none transparent; } -#g-quick-search-form label { display: none; } -#g-quick-search-form li { display: inline; float: left; padding: 0px; } - -#g-quick-search-form input[type="text"] { width: 150px; } -#g-quick-search-form input[type="submit"] { display: block; width: 23px; height: 23px; text-indent: -9999px; overflow: hidden; } - -/* modules.css - Basket ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.basketbuttons span.ui-icon { display: none; } -#payment { height: 100%; margin-left: 10px; } -#payment p { padding: 4px; } -#basketForm { width: 100%; float:right; } -#checkout { } -#checkout fieldset { border: none; } -#checkout legend { width: 100%; padding: 4px 4px 4px 8px; font-size: 1em; font-weight: bold; } -#checkout ul { padding: 8px; } -#checkout li { padding-top: 8px; display: inline; } -#checkout label { margin: 4px 0; } -#checkout select { margin: 4px 10px; } - -#checkout textarea { display: block; clear: both; padding: .2em; width: 90%; } - -/* modules.css - Register ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-welcome-message p { padding-bottom: 6px; } -#g-change-password-user-form { height: 100%; } - -/* modules.css - Localization ~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#l10n-client .labels { border-top: white 1px solid; height: 1.7em; } -#l10n-client h2 { padding-top: 0.4em; padding-bottom: 0.3em; } -#l10n-client .label.translation { margin-top: -0.4em; height: 1.7em; } -#l10n-client #l10n-client-toggler { line-height: 1.7em; height: 1.7em; } -#l10n-client .string-list li { font-size: 0.8em; line-height: 1.1em; } -#l10n-client #l10n-client-string-select { width: 24%; } -#l10n-client #l10n-client-string-select .string-list { border: 1px #ccc solid; } -#l10n-client #g-l10n-search-form ul { padding: 0; } -#l10n-client #l10n-client-string-editor { margin-left: 1em; } -#l10n-client-string-editor .source .source-text { margin: 0 0.4em 0 0; border: 1px #ccc solid; padding: 0.4em; line-height: 1em; } -#l10n-client-string-editor .translation { height: 19em; } -#l10n-client #l10n-edit-translation { width: 97%; height: 17em; border: 1px #ccc solid; font-family: monospace; padding: 0.4em; } diff --git a/3.0/themes/greydragon/css/old_ie.css b/3.0/themes/greydragon/css/old_ie.css deleted file mode 100644 index 9a5da7b8..00000000 --- a/3.0/themes/greydragon/css/old_ie.css +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * CSS rules - IE 6 hacks - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* old_ie.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -body { word-wrap: break-word; font-size: 100.1%; } - -.g-item .g-metadata:hover { padding: 0px 0 4px 6px; } -#g-quick-search-form input[type="submit"] { padding: 60px 0 0 0; } -#g-column-centerleft { margin: 0 19em 0 0; } -#g-column-centerright { margin: 0 0 0 19em; } diff --git a/3.0/themes/greydragon/css/screen.css b/3.0/themes/greydragon/css/screen.css deleted file mode 100644 index 17ecf082..00000000 --- a/3.0/themes/greydragon/css/screen.css +++ /dev/null @@ -1,224 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * CSS rules - Kitchen sync - * - * Color rules for font/background/lines can be found in dedicated colorpack files - */ - -@import url(layout.css); -@import url(menus.css); -@import url(forms.css); -@import url(modules.css); - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* screen.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -body { font-family: Arial, verdana, sans-serif; font-size: 0.9em; } - -a { text-decoration: none; outline: none; -moz-outline-style: none; } -a:focus, a:active, a:hover { text-decoration: none; outline: none; } -img { border: none; } -p { text-indent: 0; } -ul { list-style: none none; } - -h1 { font-weight: bold; font-size: 1.1em; padding-bottom: 1px; } -h2 { font-weight: bold; font-size: 1.1em; } -h3 { font-weight: bold; } -h4 { font-weight: bold; } -h5 { font-weight: bold; } - -.txtright { text-align: right; } -.g-metadata { overflow: hidden; } -.g-avatar { float: right; } - -.ui-icon { display: inline-block; zoom: 1; width: 16px; height: 15px; } -.ui-icon-first { background-position: -162px -178px; } -.ui-icon-first-d { background-position: -162px -162px; } -.ui-icon-prev { background-position: -178px -178px; } -.ui-icon-prev-d { background-position: -178px -162px; } -.ui-icon-parent { background-position: -226px -178px; } -.ui-icon-parent-d { background-position: -226px -162px; } -.ui-icon-next { background-position: -194px -178px; } -.ui-icon-next-d { background-position: -194px -162px; } -.ui-icon-last { background-position: -210px -178px; } -.ui-icon-last-d { background-position: -210px -162px; } -.ui-icon-signal-diag { background-position: -16px -178px; } -.ui-icon-info { background-position: -16px -144px; } -.ui-icon-plus { background-position: -14px -129px; } -.ui-icon-minus { background-position: -46px -129px; } -.ui-icon-note { background-position: -66px -98px; } - -.ui-icon-comment { background-position: -227px -219px; width: 27px; height: 20px; } -.ui-icon-left .ui-icon { float: left; margin-right: .2em; } -.ui-icon-right .ui-icon { float: right; margin-left: .2em; } - -/* screen.css - Header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-header { height: 90px; padding: 0; font-size: 0.9em; } - -#g-logo { position: absolute; top: 8px; left: 16px; } - -.g-breadcrumbs { position: absolute; bottom: 4px; background-color: transparent; } -.g-breadcrumbs.default { right: 14px; } -.g-breadcrumbs.left { left: 304px; padding-left: 0; } -.g-breadcrumbs li { display: inline; padding-left: 1em; padding-right: 0.4em; } -.g-breadcrumbs li.g-first { background-image: none; } -.g-breadcrumbs li.g-active { padding-right: 0; } - -#g-header .g-message-block { position: absolute; z-index: 10; min-width: 30em; padding: 4px 6px; right: 20em; top: 34px; overflow: hidden; font: bold 9pt Arial, verdana, sans-serif; text-align: center; } - -#g-header #g-login-menu { position: absolute; top: 0.5em; right: 1em; background-color: transparent; display: none; } - -/* screen.css - Main ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-main { display: block; margin: 0; } -#g-main-in { display: block; position: relative; } - -#g-column-center, #g-column-centerleft { padding: 6px 6px 6px 16px; } -#g-column-centerfull { padding: 6px 12px 6px 10px; } -#g-column-centerright { padding: 6px 12px 6px 6px; } -#g-column-left { padding: 6px 4px 6px 10px; } -#g-column-right { padding: 6px 10px 6px 4px; } - -/* screen.css - Footer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-footer { padding: 6px 6px 6px 14px; zoom: 1; font-size: 0.9em; } -#g-footer ul { float: left; padding: 0; text-align: left; } -#g-footer li { padding: 0 0 2px 0; } - -#g-footer #g-login-menu { position: absolute; bottom: 0.5em; right: 1em; background-color: transparent; display: none; } - -#g-login-menu li { display: inline; padding-left: 1.2em; } -#g-logout-link { float: none; margin-right: 0; } - -#g-copyright { font-size: x-small; } -#g-footer #g-footer-rightside { float: right; padding-right: 6px; text-align: right; } -#g-credits { margin-right: 14px; } - -/* screen.css - Pagination ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-paginator { display: inline-block; width: 100%; padding: 4px 0 0 0; zoom: 1; } -.g-paginator li { display: inline; float: left; margin-left: 0; zoom: 1; } -.g-paginator a { padding: 0 0 0 2px; } - -.g-paginator .g-pagination { width: 80%; font-size: 0.8em; } -.g-paginator .g-navigation { text-align: right; width: 20%; } - -/* screen.css - Album grid ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-album-grid { padding: 6px 0 0 0; width: 100%; display: inline-block; } -#g-album-grid .g-item { position: relative; float: left; margin: 4px 0; min-width: 212px; width: 33%; zoom: 1; } /* amargin-right: 10px; */ -#g-album-grid .g-extra-column { width: 23%; } -#g-album-grid .g-item p { text-align: center; } -#g-album-grid h2 { position: absolute; top: 164px; left: 12px; width: 150px; font: 100%/100% Arial, Helvetica, sans-serif; } -#g-album-grid h2 a { display: block; margin-top: 4px; font: bold 0.8em Arial, Helvetica, Verdana, Sans-Serif; letter-spacing: 0.1em; text-transform: uppercase; min-height: 2em; } - -/* screen.css - Thumbs : Common ~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-thumbcrop { overflow: hidden; position: relative; width: 200px; min-height: 133px; } - -.g-thumbtype-flm .g-thumbcrop { height: 150px; } -.g-thumbtype-dgt .g-thumbcrop { height: 133px; } -.g-thumbtype-sqr .g-thumbcrop { height: 200px; } -.g-album .g-description strong { padding-left: 16px; } - -/* screen.css - Thumbs : Overlay ~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-thumbslide { font-size: 0.9em; width: 208px; min-height: 139px; padding-top: 6px; padding-left: 6px; } -.g-thumbslide.g-thumbtype-flm { height: 158px; } -.g-thumbslide.g-thumbtype-dgt { height: 141px; } -.g-thumbslide.g-thumbtype-sqr { height: 208px; } - -.g-thumbcrop a.g-thumlink { display: block; position: relative; } -.g-thumbslide .g-thumbcrop .g-description { display: none; } -.g-thumbslide:hover .g-description { display: block; position: absolute; top: 0; min-height: 32px; width: 100%; overflow: hidden; z-index: 3; font-weight: bold; font-size: 0.9em; letter-spacing: 0.1em; text-transform: uppercase; text-align: left; } -.g-thumbslide:hover .g-description strong { display: block; margin-left: 10px; padding-top: 2px; } -.g-album .g-thumbslide:hover .g-description strong { padding-left: 16px; } -.g-thumbslide .g-description strong { display: block; margin-left: 10px; padding-top: 2px; } - -.g-thumbslide .g-metadata { display: none; } -.g-thumbslide:hover .g-metadata { display: block; position: absolute; bottom: 7px; margin: 0 0 1px 1px; padding: 2px 4px 2px 6px; width: 190px; } -.g-thumbslide:hover .g-metadata li { padding: 0; margin: 0; font-size: 0.9em; } -.g-album .g-thumbslide:hover .g-metadata { bottom: 10px; } - -/* screen.css - Thumbs : Extended View mode ~~~~~~~~~~~~*/ - -.g-thumbslide-ext { font-size: 0.9em; width: 208px; min-height: 139px; padding-top: 6px; padding-left: 6px; } -.g-thumbslide-ext.g-thumbtype-flm { height: 188px; } -.g-thumbslide-ext.g-thumbtype-dgt { height: 171px; } -.g-thumbslide-ext.g-thumbtype-sqr { height: 238px; } - -.g-thumbslide-ext .g-description { display: block; margin-top: 2px; width: 200px; overflow: hidden; font-weight: bold; font-size: 0.9em; letter-spacing: 0.1em; text-transform: uppercase; text-align: left; } -.g-thumbslide-ext .g-description strong { display: block; } -.g-album .g-thumbslide-ext .g-description strong { padding-left: 24px; } - -.g-thumbslide-ext .g-metadata { display: none; } -.g-thumbslide-ext:hover .g-metadata { display: block; position: absolute; bottom: 37px; margin: 0 0 1px 1px; padding: 2px 4px 2px 6px; width: 190px; } -.g-thumbslide-ext:hover .g-metadata li { padding: 0; margin: 0; font-size: 0.9em; } -.g-album .g-thumbslide-ext:hover .g-metadata { bottom: 40px; } - -/* screen.css - Photo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-item { float: left; height: 100%; width: 100%; } -#g-photo { padding: 6px 0 6px 6px; text-align: center; float: left; height: 100%; width: 100%; } -div.g-resize { position: relative; left: 50%; float: left; padding: 5px; font-size: 0.9em; } -div.g-resize>a { float: left; overflow: hidden; } -div.g-resize>a img { float: left; } -div.g-resize .g-description { display: none; } -div.g-resize:hover .g-description { position: absolute; display: block; top: 0px; margin-top: 5px; text-align: left; padding: 10px; } -div.g-resize:hover .g-description strong { display: block; margin-bottom: 5px; text-transform: uppercase; } - -div.g-resize .g-more { display: block; position: absolute; right: 16px; top: 16px; padding: 4px 8px; } -div.g-resize:hover .g-more { display: none; visibility: hidden; } - -.ul-table { text-align: center; margin: 0px auto; padding: 0; list-style-type: none; clear: both; } -.ul-table li { float: left; text-align: center; } - -#g-info { display: inline-block; width: 100%; } -#g-info .g-description { margin-top: 4px; margin-bottom: 4px; padding: 4px; } -#g-movie { padding: 6px 0 6px 6px; position: relative; } - -.g-movie { margin: 0 auto; } - -#g-albumheader h1 { margin-bottom: 6px; } - -.g-description .g-metadata { padding: 0.4em 0 0 0; font-size: 0.8em; } -.g-description .g-metadata li { display: inline; padding-right: 1em; } - -/* screen.css - Sidebar ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* screen.css - Sidebar : Common ~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-block { margin-bottom: 4px; padding-bottom: 4px; position: relative; } -.g-block h2 { padding: 4px 4px 4px 8px; font-size: 1em; } -.g-block-content { margin: 4px 6px 0 6px; display: block; zoom: 1; } - -/* screen.css - Sidebar : Buttons ~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-viewformat { z-index: 5; position: absolute; padding: 0; top: 6px; right: 10px; } -#g-viewformat li { float: left; margin-right: 2px; } -#g-viewformat span { line-height: 1px; text-indent: -900em; width: 17px; display: block; height: 15px; } -#g-viewformat span:hover, -#g-viewformat span.g-viewthumb-current { background-position: left bottom; } - -#g-view-menu { position: absolute; top: 6px; right: 70px; height: 16px; z-index: 5; zoom: 1; margin: 0 0 6px 0; padding: 0 0 4px 0; } -#g-view-menu.g-buttonset-shift { right: 6px; } -.g-toolbar { height: 1.1em; zoom: 1; margin: 0 0 4px 0; padding: 1px 0 3px 0; } -.g-menu { margin: 0; padding: 0; text-align: left; } -.g-menu li { display: inline; } - -.g-menu-element, -.g-menu-link { display: inline; float: left; margin-right: 4px; } - -.g-buttonset .g-menu-link { text-indent: -99999px; width: 22px; height: 15px; } - -#g-slideshow-link:hover, .g-fullsize-link:hover, #g-exifdata-link:hover { background-position: left bottom; } - -/* screen.css - Reauthentificate ~~~~~~~~~~~~~~~~~~~~~~ */ - -#g-reauthenticate-form fieldset { border: none; width: 260px; } -#g-reauthenticate-form ul { padding: 8px; } -#g-reauthenticate-form li { padding-top: 8px; } -#g-reauthenticate-form label { display: block; } -#g-reauthenticate-form input[type="password"] { width: 98%; } diff --git a/3.0/themes/greydragon/helpers/greydragon_theme.php b/3.0/themes/greydragon/helpers/greydragon_theme.php deleted file mode 100644 index 988da98c..00000000 --- a/3.0/themes/greydragon/helpers/greydragon_theme.php +++ /dev/null @@ -1,30 +0,0 @@ -' - . $theme_info->name . ' ' . $theme_info->version . ''; - } -} - diff --git a/3.0/themes/greydragon/images/avatar.jpg b/3.0/themes/greydragon/images/avatar.jpg deleted file mode 100644 index 71166cc4..00000000 Binary files a/3.0/themes/greydragon/images/avatar.jpg and /dev/null differ diff --git a/3.0/themes/greydragon/images/blue-grad.png b/3.0/themes/greydragon/images/blue-grad.png deleted file mode 100644 index 36e0f6bc..00000000 Binary files a/3.0/themes/greydragon/images/blue-grad.png and /dev/null differ diff --git a/3.0/themes/greydragon/images/button-grad-active-vs.png b/3.0/themes/greydragon/images/button-grad-active-vs.png deleted file mode 100644 index dc641725..00000000 Binary files a/3.0/themes/greydragon/images/button-grad-active-vs.png and /dev/null differ diff --git a/3.0/themes/greydragon/images/button-grad-vs.png b/3.0/themes/greydragon/images/button-grad-vs.png deleted file mode 100644 index 51c55a3d..00000000 Binary files a/3.0/themes/greydragon/images/button-grad-vs.png and /dev/null differ diff --git a/3.0/themes/greydragon/images/close.png b/3.0/themes/greydragon/images/close.png deleted file mode 100644 index d874f9aa..00000000 Binary files a/3.0/themes/greydragon/images/close.png and /dev/null differ diff --git a/3.0/themes/greydragon/images/donate.png b/3.0/themes/greydragon/images/donate.png deleted file mode 100644 index f36bb57a..00000000 Binary files a/3.0/themes/greydragon/images/donate.png and /dev/null differ diff --git a/3.0/themes/greydragon/images/favicon.ico b/3.0/themes/greydragon/images/favicon.ico deleted file mode 100644 index 66531d8e..00000000 Binary files a/3.0/themes/greydragon/images/favicon.ico and /dev/null differ diff --git a/3.0/themes/greydragon/images/missing-img.png b/3.0/themes/greydragon/images/missing-img.png deleted file mode 100644 index 12b7394f..00000000 Binary files a/3.0/themes/greydragon/images/missing-img.png and /dev/null differ diff --git a/3.0/themes/greydragon/js/ui.support.js b/3.0/themes/greydragon/js/ui.support.js deleted file mode 100644 index 353a30cc..00000000 --- a/3.0/themes/greydragon/js/ui.support.js +++ /dev/null @@ -1,156 +0,0 @@ -/* -* Grey Dragon Theme: JS support -*/ - -jQuery.fn.extend({ - myAjaxLoginSubmit: function() { - - var myAjaxLoginSubmitOps = { - dataType: 'json', - success: function(data) { - if (data.result == 'error') { - $('#g-login').html(data.form); - $().myAjaxLoginSubmit(); - } else { - Shadowbox.close(); - window.location.reload(); - } - } - }; - - $('form#g-login-form').one('submit', function() { - $(this).ajaxSubmit(myAjaxLoginSubmitOps); - return false; - }); - }, - - myAjaxSubmit: function() { - - var myAjaxSubmitOps = { - dataType: 'json', - success: function(data) { - if (data.result == 'error') { - $('#sb-content form').html(data.form); - $().myAjaxSubmit(); - } else { - Shadowbox.close(); - window.location.reload(); - } - } - }; - - $('form').one('submit', function() { - $(this).ajaxSubmit(myAjaxSubmitOps); - return false; - }); - }, - -/* - _ajaxify_dialog: function() { - var self = this; - $("#g-dialog form").ajaxForm({ - dataType: "json", - beforeSubmit: function(formData, form, options) { - form.find(":submit") - .addClass("ui-state-disabled") - .attr("disabled", "disabled"); - return true; - }, - success: function(data) { - if (data.form) { - var formData = unescape(data.form); - $("#g-dialog form").replaceWith(formData); - $("#g-dialog form :submit").removeClass("ui-state-disabled") - .attr("disabled", null); - self._ajaxify_dialog(); - self.form_loaded(null, $("#g-dialog form")); - if (typeof data.reset == 'function') { - eval(data.reset + '()'); - } - } - if (data.result == "success") { - if (data.location) { - window.location = data.location; - } else { - window.location.reload(); - } - } - } - }); -*/ - theme_ready: function() { - try { - Shadowbox.setup("a.g-fullsize-link", {player: 'img'}); - Shadowbox.setup("a.g-sb-preview", {player: 'img', gallery: "preview", animate: false, continuous: true, counterType: "skip", animSequence: "wh", slideshowDelay: 5 }); - - Shadowbox.setup(".g-dialog-link", {player: 'ajax', width: 500, height: 420, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup("a#g-login-link", {player: 'ajax', width: 340, height: 190, enableKeys: false, animate: false, onFinish: $().myAjaxLoginSubmit}); - Shadowbox.setup("a#g-exifdata-link", {player: 'ajax', width: 600, height: 420, animate: false}); - Shadowbox.setup("a#g-disclaimer", {player: 'ajax', width: 600, height: 420}); - - Shadowbox.setup("#g-site-menu .ui-icon-pencil", {player: 'ajax', width: 500, height: 420, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup(".g-context-menu .ui-icon-pencil", {player: 'ajax', width: 500, height: 420, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup("#g-site-menu .ui-icon-plus", {player: 'ajax', width: 500, height: 390, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup(".g-context-menu .ui-icon-plus", {player: 'ajax', width: 500, height: 390, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup("#g-site-menu .ui-icon-note", {player: 'ajax', width: 500, height: 370, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup(".g-context-menu .ui-icon-note", {player: 'ajax', width: 500, height: 370, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup("#g-site-menu .ui-icon-key", {player: 'ajax', width: 700, height: 300, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup(".g-context-menu .ui-icon-key", {player: 'ajax', width: 700, height: 300, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup("#g-site-menu #g-menu-organize-link", {player: 'ajax', width: 710, height: 460, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup(".g-context-menu #g-menu-organize-link",{player: 'ajax', width: 710, height: 460, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup(".g-context-menu .ui-icon-folder-open", {player: 'ajax', width: 400, height: 380, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup("#g-site-menu .g-quick-delete", {player: 'ajax', width: 400, height: 150, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup(".g-context-menu .ui-icon-trash", {player: 'ajax', width: 400, height: 150, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup("#g-user-profile .g-dialog-link", {player: 'ajax', width: 500, height: 280, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup("#add_to_basket .g-dialog-link", {player: 'ajax', width: 500, height: 360, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - } catch (e) { } - - try { - $(".g-message-block").fadeOut(10000); - $(".g-context-menu .g-ajax-link").gallery_ajax(); - } catch (e) { } - - $("#g-site-menu>ul>li>ul").show(); - $("#g-login-menu").show(); - $(".g-context-menu").show(); - }, - -// gallery_dialog_postprocess: function(href, title) { -// Shadowbox.open({player: 'ajax', content: href, width: 500, height: 420, enableKeys: false, animate: false, title: title, onFinish: myAjaxSubmit}); -// } -}); - -/* -(function($) { - - $.widget("ui.gallery_dialog", { - _init: function() { - var self = this; - if (!self.options.immediate) { - this.element.click(function(event) { - event.preventDefault(); - var href = $(event.currentTarget).attr("href"); - var title = $(event.currentTarget).attr("title"); - setTimeout(function() { $().gallery_dialog_postprocess(href, title); }, 1000); - return false; - }); - } else { - var href = this.element.attr("href"); - var title = this.element.attr("title"); - setTimeout(function() { $().gallery_dialog_postprocess(href, title); }, 1000); - } - } - }); -})(jQuery); -*/ - -$(document).ready(function() { - $().theme_ready(); -}); diff --git a/3.0/themes/greydragon/libraries/MY_Theme_View.php b/3.0/themes/greydragon/libraries/MY_Theme_View.php deleted file mode 100644 index 4f579ec2..00000000 --- a/3.0/themes/greydragon/libraries/MY_Theme_View.php +++ /dev/null @@ -1,313 +0,0 @@ -ensurevalue(module::get_var("th_greydragon", $key), $default)); - } - - public function load_sessioninfo() { - $this->sidebarvisible = $_REQUEST['sb']; - - if (empty($this->sidebarvisible)): - $session = Session::instance(); - $_sidebar_mode = $session->get("gd_sidebar"); - if ($_sidebar_mode): - $this->sidebarvisible = $_sidebar_mode; - else: - $this->sidebarvisible = $this->ensureoptionsvalue("sidebar_visible", "right"); - endif; - else: - // Sidebar position is kept for 360 days - Session::instance()->set("gd_sidebar", $this->sidebarvisible, time() + 31536000); - endif; - - $this->sidebarallowed = $this->ensureoptionsvalue("sidebar_allowed", "any"); - $this->sidebarvisible = $this->ensurevalue($this->sidebarvisible, "right"); - - if ($this->sidebarallowed == "none") { $this->sidebarvisible = $this->ensureoptionsvalue("sidebar_visible", "right"); }; - if ($this->sidebarallowed == "right") { $this->sidebarvisible = "right"; } - if ($this->sidebarallowed == "left") { $this->sidebarvisible = "left"; } - - if ($this->item()): - if ($this->ensureoptionsvalue("sidebar_albumonly", FALSE)): - if (!$this->item()->is_album()): - $this->sidebarallowed = "none"; - $this->sidebarvisible = "none"; - endif; - endif; - endif; - - $this->logopath = $this->ensureoptionsvalue("logo_path", url::file("lib/images/logo.png")); - $this->show_guest_menu = $this->ensureoptionsvalue("show_guest_menu", FALSE); - $this->horizontal_crop = $this->ensureoptionsvalue("horizontal_crop", FALSE); - $this->thumb_descmode = $this->ensureoptionsvalue("thumb_descmode", "overlay"); - $this->photo_descmode = $this->ensureoptionsvalue("photo_descmode", "overlay"); - $this->is_thumbmeta_visible = ((!$this->ensureoptionsvalue("hide_thumbmeta", FALSE)) and module::is_active("info")); - $this->is_photometa_visible = ((!$this->ensureoptionsvalue("hide_photometa", TRUE)) and module::is_active("info")); - $this->disable_seosupport = $this->ensureoptionsvalue("disable_seosupport", FALSE); - $this->is_blockheader_visible = (!$this->ensureoptionsvalue("hide_blockheader", FALSE)); - $this->mainmenu_position = $this->ensureoptionsvalue("mainmenu_position", "default"); - $this->show_breadcrumbs = (!$this->ensureoptionsvalue("hide_breadcrumbs", FALSE)); - $this->loginmenu_position = ($this->ensureoptionsvalue("loginmenu_position", "default")); - $this->copyright = ($this->ensureoptionsvalue("copyright", null)); - $this->photonav_position = module::get_var("th_greydragon", "photonav_position", "top"); - $this->desc_allowbbcode = $this->ensureoptionsvalue("desc_allowbbcode", FALSE); - $this->enable_pagecache = $this->ensureoptionsvalue("enable_pagecache", FALSE); - $this->color_pack = $this->ensureoptionsvalue("color_pack", "greydragon"); - - $cssfile = gallery::find_file("css/colorpacks/" . $this->color_pack, "colors.css", false); - - if (!$cssfile): - $this->color_pack = 'greydragon'; - endif; - - switch (module::get_var("th_greydragon", "thumb_ratio")): - case "digital": - $this->crop_factor = 4/3; - $this->crop_class = 'g-thumbtype-dgt'; - break; - case "square": - $this->crop_factor = 1; - $this->crop_class = 'g-thumbtype-sqr'; - break; - case "film": - $this->crop_factor = 3/2; - $this->crop_class = 'g-thumbtype-flm'; - break; - case "photo": - default: - $this->crop_factor = 1; - $this->crop_class = 'g-thumbtype-sqr'; - break; - endswitch; - - $this->_thumb_size_y = floor($this->_thumb_size_x / $this->crop_factor); - } - - public function is_sidebarallowed($align) { - return (($this->sidebarallowed == "any") or ($this->sidebarallowed == $align)); - } - - public function breadcrumb_menu($theme, $parents) { - $content = ""; - - if ($theme->item() && !empty($parents)): - $content .= ''; - endif; - - return $content; - } - - protected function sidebar_menu_item($type, $url, $caption, $css) { - if (!$this->is_sidebarallowed($type)): - return ""; - endif; - - $iscurrent = ($this->sidebarvisible == $type); - $content_menu = '
  • '; - if (!$iscurrent): - $content_menu .= ''; - endif; - $content_menu .= '' . $caption . ''; - if (!$iscurrent): - $content_menu .= ''; - endif; - - return $content_menu . '
  • '; - } - - public function sidebar_menu($url) { - if ($this->sidebarallowed != "any"): - return ""; - endif; - - $content_menu = ($this->sidebar_menu_item("left", $url, "Sidebar Left", "left")); - $content_menu .= ($this->sidebar_menu_item("none", $url, "No Sidebar", "full")); - $content_menu .= ($this->sidebar_menu_item("right", $url, "Sidebar Right", "right")); - return '
      ' . $content_menu . '
    '; - } - - public function add_paginator($position) { - if (($this->photonav_position == "both") or ($this->photonav_position == $position)): - return ($this->paginator()); - else: - return ""; - endif; - } - - public function get_thumb_element($item, $addcontext) { - $item_class = $item->is_album() ? "g-album" : "g-photo"; - - if (($this->sidebarallowed == "none") and ($this->sidebarvisible == "none")): - $item_class .= " g-extra-column"; - endif; - - $content = '
  • '; - $content .= $this->thumb_top($item); - - if (($this->crop_factor == 1) and ($item->thumb_width > $item->thumb_height)): - $_shift = 'style="margin-top: ' . floor(($this->_thumb_size_y - $item->thumb_height) / 2) . 'px;"'; - else: - if (($this->crop_factor > 0) and ($item->thumb_width < $item->thumb_height)): - $_shift = 'style="margin-top: -' . floor(($item->thumb_height - $this->_thumb_size_y) / 2) . 'px;"'; - else: - $_shift = ""; - endif; - endif; - - $content .= '
    crop_class . '">

    '; - if ($this->thumb_descmode == "overlay"): - $content .= ''; - $content .= '' . $this->bb2html(html::purify($item->title), 2) . ''; // html::purify(text::limit_chars($item->title, 44, "…")) - $content .= ''; - endif; - $content .= ''; - if (($item->thumb_height == 0) or ($item->thumb_width == 0)): - $content .= 'No Image'; - else: - $content .= $item->thumb_img(); - endif; - $content .= '

    '; - - if ($this->thumb_descmode == "bottom"): - $content .= ''; - $content .= '' . $this->bb2html(html::purify($item->title), 2) . ''; - $content .= ''; - endif; - - if (($this->is_thumbmeta_visible) and (module::is_active("info"))): - $content .= ''; - endif; - - if ($addcontext): - $_text = $this->context_menu($item, "#g-item-id-{$item->id} .g-thumbnail"); - $content .= (stripos($_text, '
  • '))? $_text : null; - endif; - - $content .= ''; - $content .= $this->thumb_bottom($item); - $content .= '
  • '; - - return $content; - } - - // $mode: bit 1 - use mix mode ($mode in [1, 3]), bit 2 - strips bbcode ($mode in [2, 3]) - public function bb2html($text, $mode) { - // Syntax Sample: - // -------------- - // [img]http://elouai.com/images/star.gif[/img] - // [url="http://elouai.com"]eLouai[/url] - // [size="25"]HUGE[/size] - // [color="red"]RED[/color] - // [b]bold[/b] - // [i]italic[/i] - // [u]underline[/u] - // [list][*]item[*]item[*]item[/list] - // [code]value="123";[/code] - // [quote]John said yadda yadda yadda[/quote] - - static $bbcode_mappings = array( - "#\\[b\\](.*?)\\[/b\\]#" => "$1", - "#\\[i\\](.*?)\\[/i\\]#" => "$1", - "#\\[u\\](.*?)\\[/u\\]#" => "$1", - "#\\[s\\](.*?)\\[/s\\]#" => "$1", - "#\\[o\\](.*?)\\[/o\\]#" => "$1", - "#\\[url\\](.*?)\[/url\\]#" => "$1", - "#\\[url=(.*?)\\](.*?)\[/url\\]#" => "$2", - "#\\[mail=(.*?)\\](.*?)\[/mail\\]#" => "$2", - "#\\[img\\](.*?)\\[/img\\]#" => "\"\"", - "#\\[img=(.*?)\\](.*?)\[/img\\]#" => "\"$2\"", - "#\\[quote\\](.*?)\\[/quote\\]#" => "

    $1

    ", - "#\\[code\\](.*?)\\[/code\\]#" => "
    $1
    ", - "#\\[size=([^\\[]*)\\]([^\\[]*)\\[/size\\]#" => "$2", - "#\\[color=([^\\[]*)\\]([^\\[]*)\\[/color\\]#" => "$2", - "#\\[class=([^\\[]*)\\]([^\\[]*)\\[/class\\]#" => "$2", - "#\\[center\\](.*?)\\[/center\\]#" => "
    $1
    ", - "#\\[list\\](.*?)\\[/list\\]#" => "
      $1
    ", - "#\\[ul\\](.*?)\\[/ul\\]#" => "
      $1
    ", - "#\\[li\\](.*?)\\[/li\\]#" => "
  • $1
  • ", - ); - - static $bbcode_strip = '|[[\/\!]*?[^\[\]]*?]|si'; - - // Replace any html brackets with HTML Entities to prevent executing HTML or script - // Don't use strip_tags here because it breaks [url] search by replacing & with amp - if (($mode == 1) or ($mode == 3)): - $newtext = str_replace("<", "<", $text); - $newtext = str_replace(">", ">", $newtext); - $newtext = str_replace(""", "\"", $newtext); - else: - $newtext = str_replace("<", "<", $text); - $newtext = str_replace(">", ">", $newtext); - $newtext = str_replace("&quot;", """, $newtext); - endif; - - // Convert new line chars to html
    tags - $newtext = nl2br($newtext); - - if (strpos($text, "[") !== false): - if (($mode == 2) or ($mode == 3)): - $newtext = preg_replace($bbcode_strip, '', $newtext); - else: - $newtext = preg_replace(array_keys($bbcode_mappings), array_values($bbcode_mappings), $newtext); - endif; - endif; - - return stripslashes($newtext); //stops slashing, useful when pulling from db - } -} - -?> \ No newline at end of file diff --git a/3.0/themes/greydragon/theme.info b/3.0/themes/greydragon/theme.info deleted file mode 100644 index cea1d8d0..00000000 --- a/3.0/themes/greydragon/theme.info +++ /dev/null @@ -1,6 +0,0 @@ -name = "Grey Dragon Theme" -description = "A Crisp flexible theme with support of Color Packs and minimized on JS overhead" -version = 2.3.1 -author = "2010 Serguei Dosyukov" -site = 1 -admin = 0 diff --git a/3.0/themes/greydragon/thumbnail.png b/3.0/themes/greydragon/thumbnail.png deleted file mode 100644 index 4b80ecaf..00000000 Binary files a/3.0/themes/greydragon/thumbnail.png and /dev/null differ diff --git a/3.0/themes/greydragon/views/album.html.php b/3.0/themes/greydragon/views/album.html.php deleted file mode 100644 index 49fa5cf4..00000000 --- a/3.0/themes/greydragon/views/album.html.php +++ /dev/null @@ -1,55 +0,0 @@ - -
    - album_top() ?> -

    bb2html(html::purify($item->title), 1) ?>

    -
    - -add_paginator("top"); ?> - -photo_descmode == "top") and ($item->description)): ?> -
    bb2html(html::purify($item->description), 1) ?>
    - - -
      - - $child): ?> - get_thumb_element($child, TRUE) ?> - - - admin || access::can("add", $item)): ?> - id") ?> -
    • Add some.", - array("attrs" => html::mark_clean("href=\"$addurl\" class=\"g-dialog-link\""))) ?>
    • - -
    • - - -
    -album_bottom() ?> - -photo_descmode == "bottom") and ($item->description)): ?> -
    bb2html(html::purify($item->description), 1) ?>
    - - -add_paginator("bottom"); ?> diff --git a/3.0/themes/greydragon/views/block.html.php b/3.0/themes/greydragon/views/block.html.php deleted file mode 100644 index af29546f..00000000 --- a/3.0/themes/greydragon/views/block.html.php +++ /dev/null @@ -1,33 +0,0 @@ - - - - -
    - is_blockheader_visible): ?> -

    - -
    - -
    -
    diff --git a/3.0/themes/greydragon/views/dynamic.html.php b/3.0/themes/greydragon/views/dynamic.html.php deleted file mode 100644 index 1f787cf3..00000000 --- a/3.0/themes/greydragon/views/dynamic.html.php +++ /dev/null @@ -1,39 +0,0 @@ - -
    -
    - dynamic_top() ?> -
    -

    -
    - -add_paginator("top"); ?> - -
      - $child): ?> - get_thumb_element($child) ?> - -
    -dynamic_bottom() ?> - -add_paginator("bottom"); ?> diff --git a/3.0/themes/greydragon/views/info_block.html.php b/3.0/themes/greydragon/views/info_block.html.php deleted file mode 100644 index d3860584..00000000 --- a/3.0/themes/greydragon/views/info_block.html.php +++ /dev/null @@ -1,24 +0,0 @@ - -
      - owner): ?> -
    • - - owner->url): ?> - owner->display_name()) ?> - - owner->display_name()) ?> - -
    • - - captured): ?> -
    • - - captured)?> -
    • - - description): ?> -
    • - bb2html(html::purify($item->description), 1) ?> -
    • - -
    diff --git a/3.0/themes/greydragon/views/login_ajax.html.php b/3.0/themes/greydragon/views/login_ajax.html.php deleted file mode 100644 index 76028c4e..00000000 --- a/3.0/themes/greydragon/views/login_ajax.html.php +++ /dev/null @@ -1,41 +0,0 @@ - - - -
    - - - - -
    - diff --git a/3.0/themes/greydragon/views/movie.html.php b/3.0/themes/greydragon/views/movie.html.php deleted file mode 100644 index ec870608..00000000 --- a/3.0/themes/greydragon/views/movie.html.php +++ /dev/null @@ -1,43 +0,0 @@ - -
    - photo_top() ?> - -
    -

    bb2html(html::purify($item->title), 1) ?>

    -
    bb2html(html::purify($item->description), 1) ?>
    -
    - - add_paginator("top"); ?> - -
    - resize_top($item) ?> - movie_img(array("class" => "g-movie", "id" => "g-movie-id-{$item->id}")); ?> - context_menu($item, "#g-movie-id-{$item->id}") ?> - resize_bottom($item) ?> -
    - - add_paginator("bottom"); ?> - - photo_bottom() ?> -
    diff --git a/3.0/themes/greydragon/views/page.html.php b/3.0/themes/greydragon/views/page.html.php deleted file mode 100644 index 13664d65..00000000 --- a/3.0/themes/greydragon/views/page.html.php +++ /dev/null @@ -1,147 +0,0 @@ - - -load_sessioninfo(); ?> - - -enable_pagecache) and ($theme->item())): - // Page will expire in 60 seconds - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 60).'GMT'); - header("Cache-Control: public"); - header("Cache-Control: post-check=3600, pre-check=43200", false); - header("Content-Type: text/html; charset=UTF-8"); - header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); - endif; -?> - - -"; ?> - - - -item()): ?> -item()->is_album()): ?> - $theme->bb2html($theme->item()->title, 2))) ?> -item()->is_photo()): ?> - $theme->bb2html($theme->item()->title, 2))) ?> - - $theme->bb2html($theme->item()->title, 2))) ?> - -tag()): ?> - $theme->bb2html($theme->tag()->name, 2))) ?> - - - - -disable_seosupport): ?> - ' . "\n"; ?> - ' . "\n"; ?> - ' . "\n"; ?> - ' . "\n"; ?> - ' . "\n"; ?> - -" type="image/x-icon" /> -script("jquery.js") ?> -script("jquery.form.js") ?> -script("jquery-ui.js") ?> -page_subtype == "movie"): ?> -script("flowplayer.js") ?> - -script("gallery.ajax.js") ?> -head() ?> -" type="text/css" media="screen,print,projection" /> -color_pack . "/colors.css") ?>" type="text/css" media="screen,print,projection" /> - - - - - - - -page_top() ?> -
    - header_top() ?> - - - - - - -guest) or ($theme->show_guest_menu)): ?> -
    "> - site_menu() ?> -
    - - messages() ?> -header_bottom() ?> - -loginmenu_position == "header"): ?> - user_menu() ?> - - -show_breadcrumbs): ?> - breadcrumb_menu($theme, $parents); ?> - -
    -
    -
    - sidebar_menu($url) ?> -
    "> - - album_menu() ?> - - photo_menu() ?> - - movie_menu() ?> - - tag_menu() ?> - -
    - - sidebarvisible=="left"): ?> - ' ?> - sidebarvisible=="none"): ?> - - ' ?> - - - page_subtype != "login") and ($theme->page_subtype != "reauthenticate") and ($theme->sidebarvisible != "none")): ?> - - - sidebarvisible != "none")? "
    " : null ?> - - sidebarvisible == "left"): ?> - ' ?> - sidebarvisible == "none"): ?> - ' ?> - - ' ?> - - -
    - - - -page_bottom() ?> - - diff --git a/3.0/themes/greydragon/views/paginator.html.php b/3.0/themes/greydragon/views/paginator.html.php deleted file mode 100644 index 9b5e725e..00000000 --- a/3.0/themes/greydragon/views/paginator.html.php +++ /dev/null @@ -1,188 +0,0 @@ - - - -parent(); - endif; - $current_page = $page; - $total_pages = $max_pages; - // Prepare page url list - for ($i = 1; $i <= $total_pages; $i++): - $_pagelist[$i] = url::site(url::merge(array("page" => $i))); - endfor; - break; - case "item": - if ($item): - $parent = $item->parent(); - endif; - $current_page = $position; - $total_pages = $total; - $siblings = $item->parent()->children(); - for ($i = 1; $i <= $total; $i++): - $_pagelist[$i] = $siblings[$i-1]->url(); - endfor; - break; - default: - $current_page = 1; - $total_pages = 1; - $_pagelist[1] = url::site(); - break; - } - - if ($total_pages <= 1): - $pagination_msg = " "; - else: - $pagination_msg = t("Page:") . ' '; - if ($total_pages < 13): - for ($i = 1; $i <= $total_pages; $i++): - if ($i == $current_page): - $pagination_msg .= '' . t($i) . ''; - else: - $pagination_msg .= '' . t($i) . ''; - endif; - if ($i < $total_pages): - $pagination_msg .= '·'; - endif; - endfor; - elseif ($current_page < 9): - for ($i = 1; $i <= 10; $i++): - if ($i == $current_page): - $pagination_msg .= '' . t($i) . ''; - else: - $pagination_msg .= '' . t($i) . ''; - endif; - if ($i < 10): - $pagination_msg .= '·'; - endif; - endfor; - - $pagination_msg .= '…'; - $pagination_msg .= '' . t($total_pages - 1) . ''; - $pagination_msg .= '·'; - $pagination_msg .= '' . t($total_pages) . ''; - - elseif ($current_page > $total_pages - 8): - $pagination_msg .= '' . t(1) . ''; - $pagination_msg .= '·'; - $pagination_msg .= '' . t(2) . ''; - $pagination_msg .= '…'; - - for ($i = $total_pages - 9; $i <= $total_pages; $i++): - if ($i == $current_page): - $pagination_msg .= '' . t($i) . ''; - else: - $pagination_msg .= '' . t($i) . ''; - endif; - if ($i < $total_pages): - $pagination_msg .= '·'; - endif; - endfor; - - else: - $pagination_msg .= '' . t(1) . ''; - $pagination_msg .= '·'; - $pagination_msg .= '' . t(2) . ''; - $pagination_msg .= '…'; - - for ($i = $current_page - 5; $i <= $current_page + 5; $i++): - if ($i == $current_page): - $pagination_msg .= '' . t($i) . ''; - else: - $pagination_msg .= '' . t($i) . ''; - endif; - if ($i < $current_page + 5): - $pagination_msg .= '·'; - endif; - endfor; - - $pagination_msg .= '…'; - $pagination_msg .= '' . t($total_pages - 1) . ''; - $pagination_msg .= '·'; - $pagination_msg .= '' . t($total_pages) . ''; - endif; - endif; -?> - - \ No newline at end of file diff --git a/3.0/themes/greydragon/views/photo.html.php b/3.0/themes/greydragon/views/photo.html.php deleted file mode 100644 index 884e30a5..00000000 --- a/3.0/themes/greydragon/views/photo.html.php +++ /dev/null @@ -1,79 +0,0 @@ - -desc_allowbbcode): ?> - bb2html($item->description, 1); ?> - - description)); ?> - - -is_photometa_visible): ?> -' . $theme->thumb_info($item) . ''; ?> - - -
    - bb2html(html::purify($item->title), 1); ?> -
    -

    -
    - add_paginator("top"); ?> - photo_top() ?> - photo_descmode == "top") and ($_description)): ?> -
    - -
    - resize_top($item) ?> - - file_url() . '" class="g-sb-preview" '; ?> - - - - resize_width; ?> - parent()->children(); ?> - -
    - rand_key != $item->rand_key)); $i++): - ?> - "> - resize_img(array("id" => "g-photo-id-{$item->id}", "class" => "g-resize", "alt" => $_title)) ?> - - - photo_descmode == "overlay") and ($_description)): ?> - More - - - - - -
    - resize_bottom($item) ?> -
    - photo_descmode == "bottom") and ($_description)): ?> -
    - - add_paginator("bottom"); ?> - photo_bottom() ?> -
    diff --git a/3.0/themes/greydragon/views/rss_block.html.php b/3.0/themes/greydragon/views/rss_block.html.php deleted file mode 100644 index 4d30ce59..00000000 --- a/3.0/themes/greydragon/views/rss_block.html.php +++ /dev/null @@ -1,13 +0,0 @@ - - diff --git a/3.0/themes/greydragon/views/search.html.php b/3.0/themes/greydragon/views/search.html.php deleted file mode 100644 index 94fc170c..00000000 --- a/3.0/themes/greydragon/views/search.html.php +++ /dev/null @@ -1,43 +0,0 @@ - -
    -

    $q)) ?>

    - - - - add_paginator("top"); ?> -
      - - is_album() ? "g-album" : "g-photo" ?> - "> ?> - get_thumb_element($item) ?> - ?> - -
    - add_paginator("bottom"); ?> - -

     

    -

    %term", array("term" => $q)) ?>

    - - -
    \ No newline at end of file diff --git a/3.0/themes/greydragon/views/sidebar.html.php b/3.0/themes/greydragon/views/sidebar.html.php deleted file mode 100644 index 0cad333d..00000000 --- a/3.0/themes/greydragon/views/sidebar.html.php +++ /dev/null @@ -1,8 +0,0 @@ - - -sidebar_top() ?> -
     
    -page_subtype == "album") or ($theme->page_subtype == "photo") or ($theme->page_subtype == "movie") or ($theme->item())): ?> -sidebar_blocks() ?> - -sidebar_bottom() ?> diff --git a/3.0/themes/greydragon/views/tag_block.html.php b/3.0/themes/greydragon/views/tag_block.html.php deleted file mode 100644 index f9bc5886..00000000 --- a/3.0/themes/greydragon/views/tag_block.html.php +++ /dev/null @@ -1,27 +0,0 @@ - - -
    "> - -
    - \ No newline at end of file diff --git a/3.0/themes/greydragon/views/user_profile.html.php b/3.0/themes/greydragon/views/user_profile.html.php deleted file mode 100644 index b7d92f40..00000000 --- a/3.0/themes/greydragon/views/user_profile.html.php +++ /dev/null @@ -1,50 +0,0 @@ - - - -
    -

    $user->display_name())) ?>

    - - - - " - alt="display_name()) ?>" - class="g-avatar g-left" width="40" height="40" /> - - - -
    -

    title) ?>

    -
    - view ?> -
    -
    - -
    diff --git a/3.0/themes/sobriety/css/comment.css b/3.0/themes/sobriety/css/comment.css new file mode 100644 index 00000000..2aeb1794 --- /dev/null +++ b/3.0/themes/sobriety/css/comment.css @@ -0,0 +1,84 @@ +#g-content #g-comments { + display: block; + margin-top: 2em; + position: relative; +} + +#g-content #g-comments h2 { + margin: 0; +} + +#g-content #g-comments #g-add-comment { + position: absolute; + right: 0; + top: 2px; +} + +#g-content #g-comments ul { + list-style-type: none; + margin: 0; + padding: 0; +} + +#g-content #g-comments #g-comment-detail > ul li { + padding: 1em 0; + border-bottom: 1px dotted #aaab9b; +} + +#g-content #g-comments ul li .g-author { + margin: 0 0 0.5em; + font-style: italic; + font-width: normal; + /*font-size: 85%;*/ +} + +#g-content #g-comments ul li .g-author a:first-child { + border: none; +} + +#g-content #g-comments ul li .g-author a img.g-avatar { + width: 13px; + height: 13px; + margin-right: 5px; +} + +#g-content #g-comments ul li div { + margin-left: 23px; +} + +#g-content #g-comments #g-comment-detail #g-comment-form fieldset { + border: 0; + margin: 1em 0 0 0; + padding: 0; +} + +#g-content #g-comments #g-comment-detail #g-comment-form fieldset legend { + font-size: 2em; + margin-bottom: 0.5em; +} + +#g-content #g-comments #g-comment-detail #g-comment-form fieldset ul li { + clear: both; + padding-top: 0.5em; +} + +#g-content #g-comments #g-comment-detail #g-comment-form fieldset ul li label { + float: left; + width: 30%; + padding-top: 5px; +} + +#g-content #g-comments #g-comment-detail #g-comment-form fieldset ul li input[type="text"] { + float: left; + width: 40%; +} + +#g-content #g-comments #g-comment-detail #g-comment-form fieldset ul li input[type="submit"] { + float: right; +} + +#g-content #g-comments #g-comment-detail #g-comment-form fieldset ul li textarea { + float: left; + width: 69%; + height: 10em; +} diff --git a/3.0/themes/sobriety/css/screen.css b/3.0/themes/sobriety/css/screen.css index ea8bfaf0..3fb13ede 100644 --- a/3.0/themes/sobriety/css/screen.css +++ b/3.0/themes/sobriety/css/screen.css @@ -60,10 +60,70 @@ div#g-header { border-bottom: 3px solid #bba; } -div#g-banner { +a#g-logo, form#g-quick-search-form, div#g-site-menu { display: none; } +#g-header-text{ + color: #fff; + font: oblique small-caps bold 1em Georgia,serif; + position: absolute; + left: 15px; + height: 1.5em; + line-height: 1.5em; +} + +ul#g-login-menu { + list-style-type: none; + + position: absolute; + top: 0; + right: 0; + + display: block; + margin: 0; + /*padding: 0.5em;*/ + padding: 0; + + width: 20em; + width: 2.5em; + height: 2.5em; + background: url('../images/icons/g-login-menu.png') no-repeat center center; + z-index: 2; +} + +ul#g-login-menu > li { + display: none; + text-align: right; + padding: 2px 0; + width: 20em; + margin-left: -17.6em ; /* -(20-2.5) */ + background-color: #fcfcfc; + color: #000; +} + +ul#g-login-menu > li:first-child { + margin-top: 2.4em; +} + +ul#g-login-menu > li > a { + margin-right: 0.5em; +} + +ul#g-login-menu > li:hover, ul#g-login-menu > li:hover > a { + background-color: #5266f3; + color: #fff; + border-color: #fff; /* a:hover */ +} + +ul#g-login-menu:hover { + background-color: #5266f3; +} + +ul#g-login-menu:hover > li { + display: block; +} + ul.g-breadcrumbs { margin: 0; padding: 0; @@ -443,15 +503,17 @@ span.ui-icon-key { background-position: -112px -128px; } background: #b7b7a7; } -#g-item #g-movie { - display: block; -} - #g-item #g-photo a { border: none; } -#g-item #g-photo a img { +#g-item #g-movie, +#g-item #g-movie a { + display: block; +} + +#g-item #g-photo img, +#g-item #g-movie object { border: 10px solid #fff; -webkit-box-shadow: 3px 3px 0px #b7b7a7; -moz-box-shadow: 3px 3px 0px #b7b7a7; @@ -531,7 +593,8 @@ span.ui-icon-key { background-position: -112px -128px; } } #g-item .g-block { - display: none; + display: block; + margin: auto; } #g-item .g-block#g-metadata { @@ -559,9 +622,6 @@ span.ui-icon-key { background-position: -112px -128px; } padding: 0; } -#g-item .g-block#g-comments { - display: block; -} @@ -590,21 +650,6 @@ span.ui-icon-key { background-position: -112px -128px; } -#g-login-menu { - position: absolute; - right: 0; - padding: 0; - margin: 0; -} -#g-login-menu li { - display: inline; -} -#g-login-menu li:first-child { - /*display: none;*/ -} -#g-logo, #g-quick-search-form, #g-site-menu { - display: none; -} @@ -754,6 +799,18 @@ div#g-action-status { height: 8em; } +#g-dialog input[type=submit].submit { + float: right; +} + +#g-dialog a.g-cancel { + float: right; + -moz-appearance: button; + -webkit-appearance: push-button; + /*clear: left;*/ +} + + #g-add-photos-canvas-sd { height: 33px; /*margin-right: 63px;*/ @@ -811,7 +868,7 @@ div#g-action-status { height: 22px; width: 0%; background-image: url("../images/backgrounds/pbar-ani.gif"); - background-repeat: x-repeat; + background-repeat: repeat-x; } #g-add-photos-progressbar.stop { background-image: url("../images/backgrounds/pbar-ani-stop.gif"); diff --git a/3.0/themes/sobriety/images/avatar.jpg b/3.0/themes/sobriety/images/avatar.jpg new file mode 100644 index 00000000..17a31829 Binary files /dev/null and b/3.0/themes/sobriety/images/avatar.jpg differ diff --git a/3.0/themes/sobriety/images/ico-denied-inactive.png b/3.0/themes/sobriety/images/ico-denied-inactive.png new file mode 100644 index 00000000..56db3ff5 Binary files /dev/null and b/3.0/themes/sobriety/images/ico-denied-inactive.png differ diff --git a/3.0/themes/sobriety/images/ico-denied-passive.png b/3.0/themes/sobriety/images/ico-denied-passive.png new file mode 100644 index 00000000..1e992230 Binary files /dev/null and b/3.0/themes/sobriety/images/ico-denied-passive.png differ diff --git a/3.0/themes/sobriety/images/ico-denied.png b/3.0/themes/sobriety/images/ico-denied.png new file mode 100644 index 00000000..08f24936 Binary files /dev/null and b/3.0/themes/sobriety/images/ico-denied.png differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/ico-error.png b/3.0/themes/sobriety/images/ico-error.png similarity index 100% rename from 3.0/themes/greydragon/css/colorpacks/carbon/images/ico-error.png rename to 3.0/themes/sobriety/images/ico-error.png diff --git a/3.0/themes/sobriety/images/ico-info.png b/3.0/themes/sobriety/images/ico-info.png new file mode 100644 index 00000000..12cd1aef Binary files /dev/null and b/3.0/themes/sobriety/images/ico-info.png differ diff --git a/3.0/themes/sobriety/images/ico-lock.png b/3.0/themes/sobriety/images/ico-lock.png new file mode 100644 index 00000000..2ebc4f6f Binary files /dev/null and b/3.0/themes/sobriety/images/ico-lock.png differ diff --git a/3.0/themes/sobriety/images/ico-separator-rtl.gif b/3.0/themes/sobriety/images/ico-separator-rtl.gif new file mode 100644 index 00000000..d9061a46 Binary files /dev/null and b/3.0/themes/sobriety/images/ico-separator-rtl.gif differ diff --git a/3.0/themes/sobriety/images/ico-separator.gif b/3.0/themes/sobriety/images/ico-separator.gif new file mode 100644 index 00000000..3de2d0d3 Binary files /dev/null and b/3.0/themes/sobriety/images/ico-separator.gif differ diff --git a/3.0/themes/sobriety/images/ico-success-inactive.png b/3.0/themes/sobriety/images/ico-success-inactive.png new file mode 100644 index 00000000..74b2032f Binary files /dev/null and b/3.0/themes/sobriety/images/ico-success-inactive.png differ diff --git a/3.0/themes/sobriety/images/ico-success-passive.png b/3.0/themes/sobriety/images/ico-success-passive.png new file mode 100644 index 00000000..dc8d1ded Binary files /dev/null and b/3.0/themes/sobriety/images/ico-success-passive.png differ diff --git a/3.0/themes/greydragon/css/colorpacks/carbon/images/ico-success.png b/3.0/themes/sobriety/images/ico-success.png similarity index 100% rename from 3.0/themes/greydragon/css/colorpacks/carbon/images/ico-success.png rename to 3.0/themes/sobriety/images/ico-success.png diff --git a/3.0/themes/sobriety/images/ico-warning.png b/3.0/themes/sobriety/images/ico-warning.png new file mode 100644 index 00000000..628cf2da Binary files /dev/null and b/3.0/themes/sobriety/images/ico-warning.png differ diff --git a/3.0/themes/sobriety/images/icon_pushpin.gif b/3.0/themes/sobriety/images/icon_pushpin.gif deleted file mode 100644 index b9e8461e..00000000 Binary files a/3.0/themes/sobriety/images/icon_pushpin.gif and /dev/null differ diff --git a/3.0/themes/sobriety/images/icons/g-login-menu.png b/3.0/themes/sobriety/images/icons/g-login-menu.png new file mode 100644 index 00000000..33e686cb Binary files /dev/null and b/3.0/themes/sobriety/images/icons/g-login-menu.png differ diff --git a/3.0/themes/sobriety/images/loading-large.gif b/3.0/themes/sobriety/images/loading-large.gif new file mode 100644 index 00000000..cc70a7a8 Binary files /dev/null and b/3.0/themes/sobriety/images/loading-large.gif differ diff --git a/3.0/themes/sobriety/images/loading-small.gif b/3.0/themes/sobriety/images/loading-small.gif new file mode 100644 index 00000000..d0bce154 Binary files /dev/null and b/3.0/themes/sobriety/images/loading-small.gif differ diff --git a/3.0/themes/sobriety/js/ui.init.js b/3.0/themes/sobriety/js/ui.init.js index 4393a04a..eeaa1b6d 100644 --- a/3.0/themes/sobriety/js/ui.init.js +++ b/3.0/themes/sobriety/js/ui.init.js @@ -90,9 +90,18 @@ $(document).ready(function() { $(this).css("top", 0).css("left", 0); // Remove the placeholder and hover class from the item $(this).removeClass("g-hover-item"); + $(this).gallery_valign(); $("#g-place-holder").remove(); } ); + + // Realign any thumbnails that change so that when we rotate a thumb it stays centered. + $(".g-item").bind("gallery.change", function() { + $(".g-item").each(function() { + $(this).height($(this).find("img").height() + 2); + }); + $(".g-item").equal_heights().gallery_valign(); + }); }*/ // Photo/Item item view diff --git a/3.0/themes/sobriety/theme.info b/3.0/themes/sobriety/theme.info index 545a0815..bcb836a6 100644 --- a/3.0/themes/sobriety/theme.info +++ b/3.0/themes/sobriety/theme.info @@ -4,5 +4,5 @@ version = 1 author = "Romain LE DISEZ" site = 1 admin = 0 -;wind commit = 3b05db2685d92ca538d7993c960b06ea32f3a8df -;wind date = Wed Jun 23 11:16:56 2010 -0700 +;wind commit = 3a9bdebafda1807bb2294c041e655f6464841bf0 +;wind date = Tue Sep 21 21:38:32 2010 -0700 diff --git a/3.0/themes/sobriety/views/album.html.php b/3.0/themes/sobriety/views/album.html.php index b9072e2b..1a56af67 100644 --- a/3.0/themes/sobriety/views/album.html.php +++ b/3.0/themes/sobriety/views/album.html.php @@ -16,7 +16,9 @@
  • thumb_top($child) ?> + has_thumb()): ?> thumb_img(array("class" => "g-thumbnail")) ?> + thumb_bottom($child) ?> context_menu($child, "#g-item-id-{$child->id} .g-thumbnail") ?> @@ -29,7 +31,7 @@ admin || access::can("add", $item)): ?> - id") ?> + id") ?>
  • Add some.", array("attrs" => html::mark_clean("href=\"$addurl\" class=\"g-dialog-link\""))) ?>
  • diff --git a/3.0/themes/sobriety/views/page.html.php b/3.0/themes/sobriety/views/page.html.php index cf10b85e..7458820f 100644 --- a/3.0/themes/sobriety/views/page.html.php +++ b/3.0/themes/sobriety/views/page.html.php @@ -23,13 +23,12 @@ - " type="image/x-icon" /> + " type="image/x-icon" /> css("_DISABLED_yui/reset-fonts-grids.css") ?> css("_DISABLED_superfish/css/superfish.css") ?> css("_DISABLED_themeroller/ui.base.css") ?> - css("_DISABLED_gallery.common.css") ?> css("screen.css") ?> - @@ -51,7 +50,7 @@ head() they get combined */ ?> page_subtype == "photo"): ?> script("_DISABLED_jquery.scrollTo.js") ?> - script("_DISABLED_gallery.show_full_size.js") ?> + script("gallery.show_full_size.js") ?> page_subtype == "movie"): ?> script("flowplayer.js") ?> @@ -90,17 +89,22 @@ > - - item()->id}" : null) ?>">title), 15) ?> + causes Gallery3 to display the page + // containing that photo. For now, we just do it for + // the immediate parent so that when you go back up a + // level you're on the right page. ?> + item()->id}" : null) ?>"> + + title, + module::get_var("gallery", "visible_title_length"))) ?> +
  • "> - item()->title), 15) ?> + item()->title, + module::get_var("gallery", "visible_title_length"))) ?>
  • diff --git a/3.0/themes/sobriety/views/photo.html.php b/3.0/themes/sobriety/views/photo.html.php index c5393547..55b5f4cd 100644 --- a/3.0/themes/sobriety/views/photo.html.php +++ b/3.0/themes/sobriety/views/photo.html.php @@ -4,10 +4,23 @@ diff --git a/3.0/themes/sobriety/views/sobriety_actions.html.php b/3.0/themes/sobriety/views/sobriety_actions.html.php index a781a558..2338546b 100644 --- a/3.0/themes/sobriety/views/sobriety_actions.html.php +++ b/3.0/themes/sobriety/views/sobriety_actions.html.php @@ -5,7 +5,7 @@ module::event("site_menu", $menu, $this->theme, ""); ?> -elements['add_menu']->elements) || isset($menu->elements['options_menu']->elements) ): ?> +elements['add_menu']->elements) || !empty($menu->elements['options_menu']->elements) ): ?>

    diff --git a/3.0/themes/three_nids/admin/helpers/three_nids_event.php b/3.0/themes/three_nids/admin/helpers/three_nids_event.php index c8a0db51..abb221fc 100644 --- a/3.0/themes/three_nids/admin/helpers/three_nids_event.php +++ b/3.0/themes/three_nids/admin/helpers/three_nids_event.php @@ -1,7 +1,7 @@ t("About This Album")); + } + + static function get($block_id, $theme) { + switch ($block_id) { + case "aboutthisalbum": + $item = $theme->item; + if ((!$item) or (!$theme->item->is_album())) { + return ""; + } + if ($theme->item->is_album()) { + $block = new Block(); + $block->css_id = "g-about-this-album"; + $block->content = new View("about_this_album.html"); + + if ($theme->item()->id == item::root()->id) { + $block->title = t("About this Site"); + $block->content->album_count = ORM::factory("item")->where("type", "=", "album")->where("id", "<>", 1)->count_all(); + $block->content->photo_count = ORM::factory("item")->where("type", "=", "photo")->count_all(); + $block->content->vcount = Database::instance()->query("SELECT SUM({items}.view_count) as c FROM {items} WHERE type=\"photo\"")->current()->c; + } Else { + $block->title = t("About this Album"); + $block->content->album_count = $item->descendants_count(array(array("type", "=", "album"))); + $block->content->photo_count = $item->descendants_count(array(array("type", "=", "photo"))); + // $block->content->vcount= $theme->item()->view_count; + $descds = $item->descendants(); + $descds_view = 0; + foreach ($descds as $descd) { + if ($descd->is_photo()) { + $descds_view += $descd->view_count; + } + } + $block->content->vcount = $descds_view; + if ($item->description) { + $block->content->description = html::clean($item->description); + } + } + + + $all_tags = ORM::factory("tag") + ->join("items_tags", "items_tags.tag_id", "tags.id") + ->join("items", "items.id", "items_tags.item_id", "LEFT") + ->where("items.parent_id", "=", $item->id) + ->order_by("tags.id", "ASC") + ->find_all(); + if (count($all_tags) > 0) { + $block->content->all_tags = $all_tags; + } + } + break; + } + return $block; + } +} diff --git a/3.1/modules/about_this_album/module.info b/3.1/modules/about_this_album/module.info new file mode 100644 index 00000000..8080a24d --- /dev/null +++ b/3.1/modules/about_this_album/module.info @@ -0,0 +1,3 @@ +name = "About this Album" +description = "Show some simple, specific and useful info about a given album" +version = 1 diff --git a/3.1/modules/about_this_album/views/about_this_album.html.php b/3.1/modules/about_this_album/views/about_this_album.html.php new file mode 100644 index 00000000..01dee4f7 --- /dev/null +++ b/3.1/modules/about_this_album/views/about_this_album.html.php @@ -0,0 +1,68 @@ + + + diff --git a/3.1/modules/about_this_photo/helpers/about_this_photo_block.php b/3.1/modules/about_this_photo/helpers/about_this_photo_block.php new file mode 100644 index 00000000..267f3904 --- /dev/null +++ b/3.1/modules/about_this_photo/helpers/about_this_photo_block.php @@ -0,0 +1,71 @@ + t("About This Photo")); + } + + static function get($block_id, $theme) { + $block = new Block(); + switch ($block_id) { + case "simple": + $item = $theme->item; + if ((!$item) or (!$item->is_photo())) { + return ""; + } + $block->css_id = "g-about-this-photo"; + $block->title = t("About this photo"); + $block->content = new View("about_this_photo.html"); + + // exif API doesn't give easy access to individual keys, so do this the hard way + if (module::is_active("exif")) { + $exif = ORM::factory("exif_record")->where("item_id", "=", $theme->item()->id)->find(); + if ($exif->loaded()) { + $exif = unserialize($exif->data); + $timestamp = strtotime($exif["DateTime"]); + //$block->content->date = gallery::date($timestamp); + $block->content->date = date('D j M Y', $timestamp); + $block->content->time = gallery::time($timestamp); + } + } + + $block->content->vcount = $theme->item()->view_count; + + // IPTC - copied more or less from iptc.php + if (module::is_active("iptc")) { + $record = ORM::factory("iptc_record")->where("item_id", "=", $theme->item()->id)->find(); + if ($record->loaded()) { + $record = unserialize($record->data); + $block->content->name = $record["ObjectName"]; + $block->content->caption = $record["Caption"]; + + } + } + + if (module::is_active("tag")) { + $block->content->tags = tag::item_tags($theme->item()); + } + break; + } + return $block; + } +} + diff --git a/3.1/modules/about_this_photo/module.info b/3.1/modules/about_this_photo/module.info new file mode 100644 index 00000000..e324ae3b --- /dev/null +++ b/3.1/modules/about_this_photo/module.info @@ -0,0 +1,3 @@ +name = "About this Photo" +description = "Show some simple, specific and useful info about a given photo" +version = 3 diff --git a/3.1/modules/about_this_photo/views/about_this_photo.html.php b/3.1/modules/about_this_photo/views/about_this_photo.html.php new file mode 100644 index 00000000..f0ef130a --- /dev/null +++ b/3.1/modules/about_this_photo/views/about_this_photo.html.php @@ -0,0 +1,34 @@ + + + diff --git a/3.1/modules/adsense/controllers/admin_adsense.php b/3.1/modules/adsense/controllers/admin_adsense.php index 13be83d8..05f0c6ad 100644 --- a/3.1/modules/adsense/controllers/admin_adsense.php +++ b/3.1/modules/adsense/controllers/admin_adsense.php @@ -1,7 +1,7 @@ content = new View("admin_albumpassword.html"); + + // Generate a form for controlling the admin section. + $view->content->albumpassword_form = $this->_get_admin_form(); + + // Display the page. + print $view; + } + + private function _get_admin_form() { + // Make a new form for changing admin settings for this module. + $form = new Forge("admin/albumpassword/saveprefs", "", "post", + array("id" => "g-album-password-admin-form")); + + // Should protected items be hidden, or completely in-accessable? + $albumpassword_group = $form->group("album_password_group"); + $albumpassword_group->checkbox("hideonly") + ->label("Only hide protected albums?") + ->checked(module::get_var("albumpassword", "hideonly")); + + // Add a save button to the form. + $albumpassword_group->submit("save_settings")->value(t("Save")); + + // Return the newly generated form. + return $form; + } + + public function saveprefs() { + // Save user specified preferences. + + // Prevent Cross Site Request Forgery + access::verify_csrf(); + + // Retrieve submitted form data. + if (Input::instance()->post("hideonly") == false) { + module::set_var("albumpassword", "hideonly", false); + } else { + module::set_var("albumpassword", "hideonly", true); + } + // Display a success message and redirect back to the TagsMap admin page. + message::success(t("Your settings have been saved.")); + url::redirect("admin/albumpassword"); + } +} diff --git a/3.1/modules/albumpassword/controllers/albumpassword.php b/3.1/modules/albumpassword/controllers/albumpassword.php index b014b749..dfedcd2c 100644 --- a/3.1/modules/albumpassword/controllers/albumpassword.php +++ b/3.1/modules/albumpassword/controllers/albumpassword.php @@ -1,7 +1,7 @@ where("album_id", "=", $id)->find(); - if ($existing_password->loaded()) { + // Check for and delete the password and any cached ids assigned to it. + $existing_password = ORM::factory("items_albumpassword")->where("album_id", "=", $id)->find_all(); + if (count($existing_password) > 0) { + foreach ($existing_password as $one_password) { + db::build()->delete("albumpassword_idcaches")->where("password_id", "=", $one_password->id)->execute(); + } db::build()->delete("items_albumpasswords")->where("album_id", "=", $id)->execute(); message::success(t("Password Removed.")); } @@ -70,9 +73,12 @@ class albumpassword_Controller extends Controller { $album_id = Input::instance()->post("item_id"); $album_password = Input::instance()->post("assignpassword_password"); - // Check for, and remove, any existing passwords. - $existing_password = ORM::factory("items_albumpassword")->where("album_id", "=", $album_id)->find(); - if ($existing_password->loaded()) { + // Check for, and remove, any existing passwords and cached ids. + $existing_password = ORM::factory("items_albumpassword")->where("album_id", "=", $album_id)->find_all(); + if (count($existing_password) > 0) { + foreach ($existing_password as $one_password) { + db::build()->delete("albumpassword_idcaches")->where("password_id", "=", $one_password->id)->execute(); + } db::build()->delete("items_albumpasswords")->where("album_id", "=", $album_id)->execute(); } @@ -82,9 +88,28 @@ class albumpassword_Controller extends Controller { $new_password->password = $album_password; $new_password->save(); + // Add the album to the id cache. + $cached_album = ORM::factory("albumpassword_idcache"); + $cached_album->password_id = $new_password->id; + $cached_album->item_id = $album_id; + $cached_album->save(); + + // Check for any sub-items within the album, add all of them to the id cache. + $items = ORM::factory("item", $album_id) + ->viewable() + ->descendants(); + if (count($items) > 0) { + foreach ($items as $one_item) { + $cached_item = ORM::factory("albumpassword_idcache"); + $cached_item->password_id = $new_password->id; + $cached_item->item_id = $one_item->id; + $cached_item->save(); + } + } + // Display a success message and close the dialog. message::success(t("Password saved.")); - json::reply(array("result" => "success")); + print "\n\n\n\n\n"; } public function logout() { @@ -112,10 +137,10 @@ class albumpassword_Controller extends Controller { // If not, close the dialog and display a rejected message. cookie::set("g3_albumpassword", $album_password); message::success(t("Password Accepted.")); - json::reply(array("result" => "success")); + print "\n\n\n\n\n"; } else { message::error(t("Password Rejected.")); - json::reply(array("result" => "success")); + print "\n\n\n\n\n"; } } @@ -129,7 +154,7 @@ class albumpassword_Controller extends Controller { $assignpassword_group->input("assignpassword_password") ->id('assignpassword_password') ->label(t("Password:")); - $form->submit("save_password")->value(t("Save")); + $assignpassword_group->submit("save_password")->value(t("Save")); // Return the newly generated form. return $form; @@ -139,12 +164,14 @@ class albumpassword_Controller extends Controller { // Generate a form for allowing visitors to enter in their passwords. $form = new Forge("albumpassword/checkpassword", "", "post", array("id" => "g-login-password-form")); + $assignpassword_group = $form->group("Enter Password") ->label(t("Enter Password:")); - $assignpassword_group->input("albumpassword_password") + $assignpassword_group->password("albumpassword_password") ->id('albumpassword_password') ->label(t("Password:")); - $form->submit("login_password")->value(t("Login")); + + $assignpassword_group->submit("")->value(t("Login")); // Return the newly generated form. return $form; diff --git a/3.1/modules/albumpassword/helpers/MY_access.php b/3.1/modules/albumpassword/helpers/MY_access.php new file mode 100644 index 00000000..bda1db32 --- /dev/null +++ b/3.1/modules/albumpassword/helpers/MY_access.php @@ -0,0 +1,49 @@ +where("item_id", "=", $item->id)->order_by("cache_id")->find_all(); + if (count($item_protected) > 0) { + $existing_password = ORM::factory("items_albumpassword")->where("id", "=", $item_protected[0]->password_id)->find(); + if ($existing_password->loaded()) { + if ((cookie::get("g3_albumpassword") != $existing_password->password) && + (identity::active_user()->id != $item->owner_id) && + (!identity::active_user()->admin)) { + throw new Kohana_404_Exception(); + } + } + } + } + } +} diff --git a/3.1/modules/albumpassword/helpers/MY_item.php b/3.1/modules/albumpassword/helpers/MY_item.php index 3e09a64d..e26b65c6 100644 --- a/3.1/modules/albumpassword/helpers/MY_item.php +++ b/3.1/modules/albumpassword/helpers/MY_item.php @@ -1,7 +1,7 @@ where("id", "=", $model->id)->find(); - // Figure out if the user can access this album. - $deny_access = false; - $existing_password = ORM::factory("items_albumpassword")->where("album_id", "=", $model->id)->find(); - if ($existing_password->loaded()) { - if ((cookie::get("g3_albumpassword") != $existing_password->password) && - (identity::active_user()->id != $album_item->owner_id)) - $deny_access = true; - } + // If the user is an admin, don't hide anything anything. + // If not, hide whatever is restricted by an album password + // that the current user is not the owner of. + if (!identity::active_user()->admin) { - // set access::DENY if necessary. - if ($deny_access == true) { - $view_restrictions = array(); - if (!identity::active_user()->admin) { - foreach (identity::group_ids_for_active_user() as $id) { - $view_restrictions[] = array("items.view_$id", "=", access::DENY); + // Display items that are not in idcaches. + $model->and_open()->join("albumpassword_idcaches", "items.id", "albumpassword_idcaches.item_id", "LEFT OUTER") + ->and_where("albumpassword_idcaches.item_id", "IS", NULL); + + // ... Unless their password id corresponds with a valid password. + $existing_password = ORM::factory("items_albumpassword")->where("password", "=", cookie::get("g3_albumpassword"))->find_all(); + if (count($existing_password) > 0) { + foreach ($existing_password as $one_password) { + $model->or_where("albumpassword_idcaches.password_id", "=", $one_password->id); } } - } - if (count($view_restrictions)) { - $model->and_open()->merge_or_where($view_restrictions)->close(); + + // Or the current user is the owner of the item. + $model->or_where("items.owner_id", "=", identity::active_user()->id)->close(); } return $model; diff --git a/3.1/modules/albumpassword/helpers/albumpassword_event.php b/3.1/modules/albumpassword/helpers/albumpassword_event.php index dd83c4d9..0c9210ea 100644 --- a/3.1/modules/albumpassword/helpers/albumpassword_event.php +++ b/3.1/modules/albumpassword/helpers/albumpassword_event.php @@ -1,7 +1,7 @@ label(t("Remove password")) ->css_id("g-album-password-remove") ->url(url::site("albumpassword/remove/" . $item->id))); - } else { - $menu->get("options_menu") - ->append(Menu::factory("dialog") - ->id("albumpassword_assign") - ->label(t("Assign password")) - ->css_id("g-album-password-assign") - ->url(url::site("albumpassword/assign/" . $item->id))); + } elseif ($item->id != 1) { + $passworded_subitems = ORM::factory("item", $item->id) + ->and_open()->join("albumpassword_idcaches", "items.id", "albumpassword_idcaches.item_id", "LEFT OUTER") + ->where("albumpassword_idcaches.item_id", "IS NOT", NULL)->close() + ->descendants(); + + $existing_cacheditem = ORM::factory("albumpassword_idcache")->where("item_id", "=", $item->id)->order_by("cache_id")->find_all(); + if ((count($existing_cacheditem) == 0) && count($passworded_subitems) == 0) { + $menu->get("options_menu") + ->append(Menu::factory("dialog") + ->id("albumpassword_assign") + ->label(t("Assign password")) + ->css_id("g-album-password-assign") + ->url(url::site("albumpassword/assign/" . $item->id))); + } } } } } static function item_deleted($item) { - // If an album is deleted, remove any associated passwords. - $existingPasswords = ORM::factory("items_albumpassword") - ->where("album_id", "=", $item->id) - ->find_all(); - if (count($existingPasswords) > 0) { - db::build()->delete("items_albumpassword")->where("album_id", "=", $item->id)->execute(); + // Check for and delete the password and any cached ids assigned to it. + $existing_password = ORM::factory("items_albumpassword")->where("album_id", "=", $item->id)->find_all(); + if (count($existing_password) > 0) { + foreach ($existing_password as $one_password) { + db::build()->delete("albumpassword_idcaches")->where("password_id", "=", $one_password->id)->execute(); + } + db::build()->delete("items_albumpasswords")->where("album_id", "=", $item->id)->execute(); + message::success(t("Password Removed.")); + } else { + db::build()->delete("albumpassword_idcaches")->where("item_id", "=", $item->id)->execute(); } } + + static function item_created($item) { + // Check for any already existing password on parent album(s), if found, generate cache data for the new item. + $existing_password = ORM::factory("albumpassword_idcache")->where("item_id", "=", $item->parent_id)->order_by("cache_id")->find_all(); + if (count($existing_password) > 0) { + $new_cachedid = ORM::factory("albumpassword_idcache"); + $new_cachedid->password_id = $existing_password[0]->password_id; + $new_cachedid->item_id = $item->id; + $new_cachedid->save(); + } + } + + static function item_moved($item, $old_parent) { + // Delete any existing cache data. + db::build()->delete("albumpassword_idcaches")->where("item_id", "=", $item->id)->execute(); + + // Check for a password on the new parent, generate cache data if necessary. + $existing_password = ORM::factory("albumpassword_idcache")->where("item_id", "=", $item->parent_id)->order_by("cache_id")->find_all(); + if (count($existing_password) > 0) { + $new_cachedid = ORM::factory("albumpassword_idcache"); + $new_cachedid->password_id = $existing_password[0]->password_id; + $new_cachedid->item_id = $item->id; + $new_cachedid->save(); + } + } + + static function admin_menu($menu, $theme) { + // Add a link to the Album Password admin page to the Content menu. + $menu->get("settings_menu") + ->append(Menu::factory("link") + ->id("albumpassword") + ->label(t("Album Password Settings")) + ->url(url::site("admin/albumpassword"))); + } } diff --git a/3.1/modules/albumpassword/helpers/albumpassword_installer.php b/3.1/modules/albumpassword/helpers/albumpassword_installer.php index e59faffb..93a6d0c0 100644 --- a/3.1/modules/albumpassword/helpers/albumpassword_installer.php +++ b/3.1/modules/albumpassword/helpers/albumpassword_installer.php @@ -1,7 +1,7 @@ query("CREATE TABLE IF NOT EXISTS {albumpassword_idcaches} ( + `cache_id` int(9) NOT NULL auto_increment, + `password_id` int(9) NOT NULL, + `item_id` int(9) NOT NULL, + PRIMARY KEY (`cache_id`)) + DEFAULT CHARSET=utf8;"); + + // Set the default value for this module's behavior. + module::set_var("albumpassword", "hideonly", true); // Set the module's version number. - module::set_version("albumpassword", 1); + module::set_version("albumpassword", 3); + } + + static function upgrade($version) { + $db = Database::instance(); + if ($version == 1) { + // Set the default value for this module's behavior. + module::set_var("albumpassword", "hideonly", true); + module::set_version("albumpassword", $version = 2); + } + if ($version == 2) { + // Create a table to store a list of all protected items in. + $db->query("CREATE TABLE IF NOT EXISTS {albumpassword_idcaches} ( + `cache_id` int(9) NOT NULL auto_increment, + `password_id` int(9) NOT NULL, + `item_id` int(9) NOT NULL, + PRIMARY KEY (`cache_id`)) + DEFAULT CHARSET=utf8;"); + module::set_version("albumpassword", $version = 3); + } } static function uninstall() { // Delete the password table before uninstalling. $db = Database::instance(); - $db->query("DROP TABLE IF EXISTS {items_albumpassword};"); + $db->query("DROP TABLE IF EXISTS {items_albumpasswords};"); + $db->query("DROP TABLE IF EXISTS {albumpassword_idcaches};"); module::delete("albumpassword"); } } diff --git a/3.1/modules/albumpassword/helpers/albumpassword_task.php b/3.1/modules/albumpassword/helpers/albumpassword_task.php new file mode 100644 index 00000000..b6ea007a --- /dev/null +++ b/3.1/modules/albumpassword/helpers/albumpassword_task.php @@ -0,0 +1,138 @@ +join("albumpassword_idcaches", "items_albumpasswords.id", "albumpassword_idcaches.password_id", "LEFT OUTER") + ->and_where("albumpassword_idcaches.password_id", "IS", NULL)->count_all(); + + return array(Task_Definition::factory() + ->callback("albumpassword_task::update_idcaches") + ->name(t("Rebuild Album Password ID Caches DB")) + ->description(t("Logs the contents of all protected albums into the db.")) + ->severity($bad_albums ? log::WARNING : log::SUCCESS)); + } + + static function update_idcaches($task) { + // Populate the idcaches table with the contents of all protected albums. + + $start = microtime(true); + $total = $task->get("total"); + $existing_passwords = ORM::factory("items_albumpassword")->find_all(); + // If this is the first time this function has been run, + // delete and re-create the idcaches table, and set up + // some initial variables. + if (empty($total)) { + // Delete the idcache table and make a new one. + $db = Database::instance(); + $db->query("DROP TABLE IF EXISTS {albumpassword_idcaches};"); + $db->query("CREATE TABLE IF NOT EXISTS {albumpassword_idcaches} ( + `cache_id` int(9) NOT NULL auto_increment, + `password_id` int(9) NOT NULL, + `item_id` int(9) NOT NULL, + PRIMARY KEY (`cache_id`)) + DEFAULT CHARSET=utf8;"); + + // Set the initial values for all variables. + $task->set("total", count($existing_passwords)); + $total = $task->get("total"); + $task->set("last_album_counter", 0); + $task->set("last_id", 0); + $task->set("completed_albums", 0); + $task->set("completed_items", 0); + $task->set("total_items", 0); + } + + // Retrieve the values for variables from the last time this + // function was run. + $last_album_counter = $task->get("last_album_counter"); + $completed_albums = $task->get("completed_albums"); + $completed_items = $task->get("completed_items"); + $total_items = $task->get("total_items"); + $last_id = $task->get("last_id"); + + // If completed_items is 0, then we're just starting to process this + // album. Add the album to idcaches before adding it's contents. + if ($completed_items == 0) { + // Add the album to the id cache. + $cached_album = ORM::factory("albumpassword_idcache"); + $cached_album->password_id = $existing_passwords[$last_album_counter]->id; + $cached_album->item_id = $existing_passwords[$last_album_counter]->album_id; + $cached_album->save(); + + // Set total_items to the number of items in this album. + $total_items = ORM::factory("item", $existing_passwords[$last_album_counter]->album_id) + ->descendants_count(); + $task->set("total_items", $total_items); + } + + // Add each item in the album to idcaches. + foreach (ORM::factory("item", $existing_passwords[$last_album_counter]->album_id) + ->where("id", ">", $last_id) + ->order_by("id") + ->descendants(100) as $item) { + + $cached_item = ORM::factory("albumpassword_idcache"); + $cached_item->password_id =$existing_passwords[$last_album_counter]->id; + $cached_item->item_id = $item->id; + $cached_item->save(); + + $last_id = $item->id; + $completed_items++; + + // Set a time limit so the script doesn't time out. + if (microtime(true) - $start > 1.5) { + break; + } + } // end foreach + + // If completed_items equals total_items, then we've + // processed everything in the current album. + // Increase variables and set everything up for the + // next album. + if ($completed_items == $total_items) { + $completed_items = 0; + $last_album_counter++; + $completed_albums++; + $last_id = 0; + } + + // Store the current values of the variables for the next + // time this function is called. + $task->set("last_album_counter", $last_album_counter); + $task->set("last_id", $last_id); + $task->set("completed_albums", $completed_albums); + $task->set("completed_items", $completed_items); + + // Display the number of albums that have been completed before exiting. + if ($total == $completed_albums) { + $task->done = true; + $task->state = "success"; + $task->percent_complete = 100; + $task->status = t("Scanning Protected Album $completed_albums of $total"); + } else { + $task->percent_complete = round(100 * $completed / $total); + $task->status = t("Scanning Protected Album $completed_albums of $total -- $completed_items / $total_items files"); + } + } +} diff --git a/3.1/modules/albumpassword/models/albumpassword_idcache.php b/3.1/modules/albumpassword/models/albumpassword_idcache.php new file mode 100644 index 00000000..e3d80667 --- /dev/null +++ b/3.1/modules/albumpassword/models/albumpassword_idcache.php @@ -0,0 +1,21 @@ + +

    + +

    +
    +
    +

    + +
    diff --git a/3.1/modules/albumpassword/views/assignpassword.html.php b/3.1/modules/albumpassword/views/assignpassword.html.php index 14cd2767..c1a60b8d 100644 --- a/3.1/modules/albumpassword/views/assignpassword.html.php +++ b/3.1/modules/albumpassword/views/assignpassword.html.php @@ -1,20 +1,3 @@ -
    • diff --git a/3.1/modules/albumpassword/views/loginpassword.html.php b/3.1/modules/albumpassword/views/loginpassword.html.php index 9ebb47fd..750ffbed 100644 --- a/3.1/modules/albumpassword/views/loginpassword.html.php +++ b/3.1/modules/albumpassword/views/loginpassword.html.php @@ -1,20 +1,3 @@ -
      diff --git a/3.1/modules/contactowner/controllers/admin_contactowner.php b/3.1/modules/contactowner/controllers/admin_contactowner.php index 73a82ee3..26b684ab 100644 --- a/3.1/modules/contactowner/controllers/admin_contactowner.php +++ b/3.1/modules/contactowner/controllers/admin_contactowner.php @@ -1,7 +1,7 @@ /** * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2010 Bharat Mediratta + * Copyright (C) 2000-2011 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/3.1/modules/developer/views/block.txt.php b/3.1/modules/developer/views/block.txt.php index aae11c89..28a8d9db 100644 --- a/3.1/modules/developer/views/block.txt.php +++ b/3.1/modules/developer/views/block.txt.php @@ -3,7 +3,7 @@ /** * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2010 Bharat Mediratta + * Copyright (C) 2000-2011 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/3.1/modules/developer/views/controller.txt.php b/3.1/modules/developer/views/controller.txt.php index b73ae815..664ff987 100644 --- a/3.1/modules/developer/views/controller.txt.php +++ b/3.1/modules/developer/views/controller.txt.php @@ -2,7 +2,7 @@ /** * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2010 Bharat Mediratta + * Copyright (C) 2000-2011 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/3.1/modules/developer/views/event.txt.php b/3.1/modules/developer/views/event.txt.php index ac5db4e3..32a48520 100644 --- a/3.1/modules/developer/views/event.txt.php +++ b/3.1/modules/developer/views/event.txt.php @@ -2,7 +2,7 @@ /** * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2010 Bharat Mediratta + * Copyright (C) 2000-2011 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/3.1/modules/developer/views/installer.txt.php b/3.1/modules/developer/views/installer.txt.php index 6748ac46..cf6662d5 100644 --- a/3.1/modules/developer/views/installer.txt.php +++ b/3.1/modules/developer/views/installer.txt.php @@ -2,7 +2,7 @@ /** * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2010 Bharat Mediratta + * Copyright (C) 2000-2011 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/3.1/modules/developer/views/theme.txt.php b/3.1/modules/developer/views/theme.txt.php index 190ff828..e4467f43 100644 --- a/3.1/modules/developer/views/theme.txt.php +++ b/3.1/modules/developer/views/theme.txt.php @@ -2,7 +2,7 @@ /** * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2010 Bharat Mediratta + * Copyright (C) 2000-2011 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/3.1/modules/displaytags/helpers/displaytags_block.php b/3.1/modules/displaytags/helpers/displaytags_block.php index ea63bb77..8fc530f1 100644 --- a/3.1/modules/displaytags/helpers/displaytags_block.php +++ b/3.1/modules/displaytags/helpers/displaytags_block.php @@ -1,7 +1,7 @@ module == "tag") { + $data->messages["warn"][] = t("The DisplayTags module requires the Tags module."); + } + } + + static function module_change($changes) { + if (!module::is_active("tag") || in_array("tag", $changes->deactivate)) { + site_status::warning( + t("The DisplayTags module requires the Tags module. Activate the Tags module now", + array("url" => html::mark_clean(url::site("admin/modules")))), + "displaytags_needs_tag"); + } else { + site_status::clear("displaytags_needs_tag"); + } + } +} diff --git a/3.1/themes/greydragon/helpers/greydragon_installer.php b/3.1/modules/displaytags/helpers/displaytags_installer.php similarity index 66% rename from 3.1/themes/greydragon/helpers/greydragon_installer.php rename to 3.1/modules/displaytags/helpers/displaytags_installer.php index 461e6914..808def8a 100644 --- a/3.1/themes/greydragon/helpers/greydragon_installer.php +++ b/3.1/modules/displaytags/helpers/displaytags_installer.php @@ -1,30 +1,36 @@ - \ No newline at end of file +init($id); - $files = $this->getFilesList($album); + public function zip($container_type, $id) { + switch($container_type) { + case "album": + $container = ORM::factory("item", $id); + if (!$container->is_album()) { + throw new Kohana_Exception('container is not an album: '.$container->relative_path()); + } + + $zipname = (empty($container->name)) + ? 'Gallery.zip' // @todo purified_version_of($container->title).'.zip' + : $container->name.'.zip'; + break; + + case "tag": + // @todo: if the module is not installed, it crash + $container = ORM::factory("tag", $id); + if (is_null($container->name)) { + throw new Kohana_Exception('container is not a tag: '.$id); + } + + $zipname = $container->name.'.zip'; + break; + + default: + throw new Kohana_Exception('unhandled container type: '.$container_type); + } + + $files = $this->getFilesList($container); // Calculate ZIP size (look behind for details) $zipsize = 22; - foreach($files as $f) { - $zipsize += 76 + 2*strlen($f) + filesize($f); + foreach($files as $f_name => $f_path) { + $zipsize += 76 + 2*strlen($f_name) + filesize($f_path); } // Send headers $this->prepareOutput(); - $this->sendHeaders($album->name.'.zip', $zipsize); + $this->sendHeaders($zipname, $zipsize); // Generate and send ZIP file // http://www.pkware.com/documents/casestudies/APPNOTE.TXT (v6.3.2) $lfh_offset = 0; $cds = ''; $cds_offset = 0; - foreach($files as $f) { - $f_namelen = strlen($f); - $f_size = filesize($f); - $f_mtime = $this->unix2dostime(filemtime($f)); - $f_crc32 = $this->fixBug45028(hexdec(hash_file('crc32b', $f, false))); + foreach($files as $f_name => $f_path) { + $f_namelen = strlen($f_name); + $f_size = filesize($f_path); + $f_mtime = $this->unix2dostime(filemtime($f_path)); + $f_crc32 = $this->fixBug45028(hexdec(hash_file('crc32b', $f_path, false))); // Local file header echo pack('VvvvVVVVvva' . $f_namelen, @@ -60,12 +85,12 @@ class downloadalbum_Controller extends Controller { $f_namelen, // file name length (2 bytes) 0, // extra field length (2 bytes) - $f // file name (variable size) + $f_name // file name (variable size) // extra field (variable size) => n/a ); // File data - readfile($f); + readfile($f_path); // Data descriptor (n/a) @@ -88,7 +113,7 @@ class downloadalbum_Controller extends Controller { 0x81b40000, // external file attributes (4 bytes) => chmod 664 $lfh_offset, // relative offset of local header (4 bytes) - $f // file name (variable size) + $f_name // file name (variable size) // extra field (variable size) => n/a // file comment (variable size) => n/a ); @@ -128,59 +153,58 @@ class downloadalbum_Controller extends Controller { } - /** - * Init - */ - private function init($id) { - $item = ORM::factory("item", $id); - - // Only send an album - if (!$item->is_album()) { - // @todo: throw an exception? - Kohana::log('error', 'item is not an album: '.$item->relative_path()); - exit; - } - - // Must have view_full to download the originals files - access::required("view_full", $item); - - return $item; - } - /** * Return the files that must be included in the archive. */ - private function getFilesList($album) { + private function getFilesList($container) { $files = array(); - // Go to the parent of album so the ZIP will not contains all the - // server hierarchy - if (!chdir($album->file_path().'/../')) { - // @todo: throw an exception? - Kohana::log('error', 'unable to chdir('.$item->file_path().'/../)'); - exit; - } - $cwd = getcwd(); + if( $container instanceof Item_Model && $container->is_album() ) { + $container_realpath = realpath($container->file_path().'/../'); - $items = $album->viewable() - ->descendants(null, null, array(array("type", "<>", "album"))); - foreach($items as $i) { - if (!access::can('view_full', $i)) { - continue; + $items = $container->viewable() + ->descendants(null, null, array(array("type", "<>", "album"))); + foreach($items as $i) { + if (!access::can('view_full', $i)) { + continue; + } + + $i_realpath = realpath($i->file_path()); + if (!is_readable($i_realpath)) { + continue; + } + + $i_relative_path = str_replace($container_realpath.DIRECTORY_SEPARATOR, '', $i_realpath); + $i_relative_path = str_replace(DIRECTORY_SEPARATOR, '/', $i_relative_path); + $files[$i_relative_path] = $i_realpath; } - $relative_path = str_replace($cwd.'/', '', realpath($i->file_path())); - if (!is_readable($relative_path)) { - continue; - } + } else if( $container instanceof Tag_Model ) { + $items = $container->items(); + foreach($items as $i) { + if (!access::can('view_full', $i)) { + continue; + } - $files[] = $relative_path; + if( $i->is_album() ) { + foreach($this->getFilesList($i) as $f_name => $f_path) { + $files[$container->name.'/'.$f_name] = $f_path; + } + + } else { + $i_realpath = realpath($i->file_path()); + if (!is_readable($i_realpath)) { + continue; + } + + $i_relative_path = $container->name.'/'.$i->name; + $files[$i_relative_path] = $i_realpath; + } + } } if (count($files) === 0) { - // @todo: throw an exception? - Kohana::log('error', 'no zippable files in ['.$album->relative_path().']'); - exit; + throw new Kohana_Exception('no zippable files in ['.$container->name.']'); } return $files; @@ -264,9 +288,13 @@ class downloadalbum_Controller extends Controller { * See http://bugs.php.net/bug.php?id=45028 */ private function fixBug45028($hash) { - return (version_compare(PHP_VERSION, '5.2.7', '<')) - ? (($hash & 0x000000ff) << 24) + (($hash & 0x0000ff00) << 8) - + (($hash & 0x00ff0000) >> 8) + (($hash & 0xff000000) >> 24) - : $hash; + $output = $hash; + + if( version_compare(PHP_VERSION, '5.2.7', '<') ) { + $str = str_pad(dechex($hash), 8, '0', STR_PAD_LEFT); + $output = hexdec($str{6}.$str{7}.$str{4}.$str{5}.$str{2}.$str{3}.$str{0}.$str{1}); + } + + return $output; } } diff --git a/3.1/modules/downloadalbum/helpers/downloadalbum_event.php b/3.1/modules/downloadalbum/helpers/downloadalbum_event.php index e2fe4420..e8159003 100644 --- a/3.1/modules/downloadalbum/helpers/downloadalbum_event.php +++ b/3.1/modules/downloadalbum/helpers/downloadalbum_event.php @@ -1,7 +1,7 @@ item)) { - $downloadLink = url::site("downloadalbum/zip/{$theme->item->id}"); - $menu - ->append(Menu::factory("link") - ->id("downloadalbum") - ->label(t("Download Album")) - ->url($downloadLink) - ->css_id("g-download-album-link")); - } + $downloadLink = url::site("downloadalbum/zip/album/{$theme->item->id}"); + $menu + ->append(Menu::factory("link") + ->id("downloadalbum") + ->label(t("Download Album")) + ->url($downloadLink) + ->css_id("g-download-album-link")); } + + static function tag_menu($menu, $theme) { + $downloadLink = url::site("downloadalbum/zip/tag/{$theme->tag()->id}"); + $menu + ->append(Menu::factory("link") + ->id("downloadalbum") + ->label(t("Download Album")) + ->url($downloadLink) + ->css_id("g-download-album-link")); + } } diff --git a/3.1/modules/downloadalbum/helpers/downloadalbum_theme.php b/3.1/modules/downloadalbum/helpers/downloadalbum_theme.php index 2fd23552..8cda59fc 100644 --- a/3.1/modules/downloadalbum/helpers/downloadalbum_theme.php +++ b/3.1/modules/downloadalbum/helpers/downloadalbum_theme.php @@ -1,7 +1,7 @@ item && access::can("view_full", $theme->item)) { - $theme->css("downloadalbum_menu.css"); - } + return $theme->css("downloadalbum_menu.css"); } } diff --git a/3.1/modules/downloadalbum/module.info b/3.1/modules/downloadalbum/module.info index 177ad4a8..11c52ba2 100644 --- a/3.1/modules/downloadalbum/module.info +++ b/3.1/modules/downloadalbum/module.info @@ -1,3 +1,3 @@ name = "DownloadAlbum" description = "Displays a link to download a ZIP archive of the current album." -version = 1 +version = 2 diff --git a/3.1/modules/downloadfullsize/controllers/admin_downloadfullsize.php b/3.1/modules/downloadfullsize/controllers/admin_downloadfullsize.php index 1b55bd5c..6836c9c8 100644 --- a/3.1/modules/downloadfullsize/controllers/admin_downloadfullsize.php +++ b/3.1/modules/downloadfullsize/controllers/admin_downloadfullsize.php @@ -1,7 +1,7 @@ item && access::can("view_full", $theme->item)) { - $theme->css("downloadfullsize_menu.css"); + return $theme->css("downloadfullsize_menu.css"); } } } diff --git a/3.1/modules/dynamic/controllers/admin_dynamic.php b/3.1/modules/dynamic/controllers/admin_dynamic.php index 0180fef3..0f87329f 100644 --- a/3.1/modules/dynamic/controllers/admin_dynamic.php +++ b/3.1/modules/dynamic/controllers/admin_dynamic.php @@ -1,6 +1,6 @@ _get_admin_form(); if ($form->validate()) { - module::set_var("ecard", "sender", $form->ecard->sender->value); + module::set_var("ecard","send_plain",$form->ecard->send_plain->value); + module::set_var("ecard", "sender", $form->ecard->sender->value); module::set_var("ecard", "bcc", $form->ecard->bcc->value); module::set_var("ecard", "subject", $form->ecard->subject->value); module::set_var("ecard", "message", $form->ecard->message->value); + module::set_var("ecard", "max_length", $form->ecard->max_length->value); module::set_var("ecard", "access_permissions", $form->ecard->access_permissions->value); module::set_var("ecard", "location", $form->ecard->location->value); message::success(t("eCard settings updated")); @@ -54,9 +56,18 @@ class Admin_ecard_Controller extends Admin_Controller { ->value(module::get_var("ecard", "bcc", "")); $ecard_settings->input("subject")->label(t("E-mail subject")) ->value(module::get_var("ecard", "subject")); - $ecard_settings->textarea("message")->label(t("E-mail message. Valid keywords are \"%toname\" (recipient's name) and \"%fromname\" (sender's name))")) + $ecard_settings->textarea("message")->label(t("E-mail message. Valid keywords are \"%fromname\" (sender's name))")) ->value(module::get_var("ecard", "message")); - $ecard_settings->dropdown("access_permissions") + $ecard_settings->input("max_length") + ->label(t("Maximum message length")) + ->value(module::get_var("ecard","max_length")); + if(module::is_active("watermark")) { + $ecard_settings->checkbox("send_plain") + ->label(t("Allow users to send non-watermarked versions")) + ->value(true) + ->checked(module::get_var("ecard","send_plain")); + } + $ecard_settings->dropdown("access_permissions") ->label(t("Who can send eCards?")) ->options(array("everybody" => t("Everybody"), "registered_users" => t("Only registered users"))) diff --git a/3.1/modules/ecard/controllers/ecard.php b/3.1/modules/ecard/controllers/ecard.php index 6ca30df7..82777443 100644 --- a/3.1/modules/ecard/controllers/ecard.php +++ b/3.1/modules/ecard/controllers/ecard.php @@ -1,7 +1,7 @@ item = $item; - $v->subject = module::get_var("ecard", "subject"); - $to_name = $form->send_ecard->to_name->value; - $from_name = $form->send_ecard->from_name->value; - $bcc = module::get_var("ecard", "bcc"); - $v->message = t(module::get_var("ecard", "message"), array("toname" => $to_name, "fromname" => $from_name)); - $v->custom_message = $form->send_ecard->text->value; - $v->image = $item->name; - $to = $form->send_ecard->inputs["to_email"]->value; - $from = $form->send_ecard->inputs["from_email"]->value; - $headers = array("from" => $from_name."<".$from.">", "to" => $to, "subject" => module::get_var("ecard", "subject")); - require_once(MODPATH. "ecard/lib/mime.php"); - $mime = new Mail_mime("\n"); - $mime->setHTMLBody($v->render()); - $mime->addHTMLImage($item->resize_path(),$item->mime_type,$item->name); - $body = $mime->get(array('html_charset' => 'UTF-8', 'text_charset' => 'UTF-8','text_encoding' => '8bit','head_charset' => 'UTF-8')); - self::_notify($headers['to'], $headers['from'], $headers['subject'], $item, $body, $mime->headers(), $bcc); + $to_array = explode(",",$form->send_ecard->inputs["to_email"]->value); + foreach($to_array as $to) { + $v = new View("ecard_email.html"); + $v->item = $item; + $v->subject = module::get_var("ecard", "subject"); + $from_name = $form->send_ecard->from_name->value; + $bcc = module::get_var("ecard", "bcc"); + if($form->send_ecard->send_to_self->checked == true) { + $cc = $form->send_ecard->inputs["from_email"]->value; + } + $v->message = t(module::get_var("ecard", "message"), array("fromname" => $from_name)); + $v->custom_message = $form->send_ecard->text->value; + $v->image = $item->name; + $from = $form->send_ecard->inputs["from_email"]->value; + $headers = array("from" => $from_name."<".$from.">", "to" => $to, "subject" => module::get_var("ecard", "subject")); + require_once(MODPATH. "ecard/lib/mime.php"); + $mime = new Mail_mime("\n"); + $mime->setHTMLBody($v->render()); + if($form->send_ecard->send_fresh->checked == true) { + $tmpfile = tempnam(TMPPATH, "clean"); + if($form->send_ecard->send_thumbnail->checked == true) { + $options = array("width" => module::get_var("gallery", "thumb_size"), "height" => module::get_var("gallery", "thumb_size"), "master" => Image::AUTO); + gallery_graphics::resize($item->file_path(), $tmpfile, $options); + $mime->addHTMLImage($tmpfile,$item->mime_type,$item->name); + } else { + $options = array("width" => module::get_var("gallery", "resize_size"), "height" => module::get_var("gallery", "resize_size"), "master" => Image::AUTO); + gallery_graphics::resize($item->file_path(), $tmpfile, $options); + $mime->addHTMLImage($tmpfile,$item->mime_type,$item->name); + } + } else { + if($form->send_ecard->send_thumbnail->checked == true) { + $mime->addHTMLImage($item->thumb_path(),$item->mime_type,$item->name); + } else { + $mime->addHTMLImage($item->resize_path(),$item->mime_type,$item->name); + } + } + $body = $mime->get(array('html_charset' => 'UTF-8', 'text_charset' => 'UTF-8','text_encoding' => '8bit','head_charset' => 'UTF-8')); + self::_notify($headers['to'], $headers['from'], $headers['subject'], $item, $body, $mime->headers(), $bcc, $cc); + } + unlink($tmpfile); message::success("eCard successfully sent"); json::reply(array("result" => "success")); - } else { + } else { json::reply(array("result" => "error", "html" => (string) $form)); - } + } } /** * Present a form for sending a new ecard. @@ -73,9 +95,11 @@ class Ecard_Controller extends Controller { if (!ecard::can_send_ecard()) { access::forbidden(); } - print ecard::prefill_send_form(ecard::get_send_form($item)); + $v_form = new View("ecard_form.html"); + $v_form->item_id = $item_id; + print $v_form->render(); } - private static function _notify($to, $from, $subject, $item, $text, $headers, $bcc) { + private static function _notify($to, $from, $subject, $item, $text, $headers, $bcc, $cc) { $sendmail = Sendmail::factory(); $sendmail ->to($to) @@ -84,6 +108,9 @@ class Ecard_Controller extends Controller { if(isset($bcc)) { $sendmail->header("bcc",$bcc); } + if(isset($cc)) { + $sendmail->header("cc",$cc); + } foreach($headers as $key => $value) { $sendmail->header($key,$value); } diff --git a/3.1/modules/ecard/helpers/ecard.php b/3.1/modules/ecard/helpers/ecard.php index 13485954..a786521b 100644 --- a/3.1/modules/ecard/helpers/ecard.php +++ b/3.1/modules/ecard/helpers/ecard.php @@ -1,7 +1,7 @@ id}", "", "post", array("id" => "g-ecard-form")); + static function get_send_form($item_id) { + $form = new Forge("ecard/send/{$item_id}", "", "post", array("id" => "g-ecard-form")); $group = $form->group("send_ecard")->label(t("Send eCard")); $group->input("from_name") ->label(t("Your name")) @@ -38,23 +38,32 @@ class ecard_Core { ->rules("required|valid_email") ->error_messages("required", t("You must enter a valid email address")) ->error_messages("invalid", t("You must enter a valid email address")); - $group->input("to_name") - ->label(t("Recipient's Name")) - ->id("g-recipient") - ->rules("required") - ->error_messages("required", t("You must enter a recipient's name")); $group->input("to_email") - ->label(t("Recipient's e-mail")) + ->label(t("Recipient's e-mail. Separate multiple recipients with a comma.")) ->id("g-recip-email") - ->rules("required|valid_email") - ->error_messages("required", t("You must enter a valid email address")) - ->error_messages("invalid", t("You must enter a valid email address")); + ->rules("required") + ->error_messages("required", t("You must enter a valid email address")); $group->textarea("text") - ->label(t("Message")) + ->label(t("Message (".module::get_var("ecard","max_length")." chars max)")) ->id("g-text") + ->maxlength(module::get_var("ecard","max_length")) ->rules("required") ->error_messages("required", t("You must enter a message")); - $group->hidden("item_id")->value($item->id); + $group->checkbox("send_to_self") + ->label(t("Send yourself a copy")) + ->value(true) + ->checked(false); + $group->checkbox("send_thumbnail") + ->label(t("Send thumbnail image, instead of resized image.")) + ->value(true) + ->checked(false); + if(module::get_var("ecard","send_plain") == true && module::is_active("watermark")) { + $group->checkbox("send_fresh") + ->label(t("Send non-watermarked image.")) + ->value(true) + ->checked(false); + } + $group->hidden("item_id")->value($item_id); module::event("ecard_send_form", $form); module::event("captcha_protect_form", $form); $group->submit("")->value(t("Send"))->class("ui-state-default ui-corner-all"); diff --git a/3.1/modules/ecard/helpers/ecard_block.php b/3.1/modules/ecard/helpers/ecard_block.php index 051c55c6..d90755ab 100644 --- a/3.1/modules/ecard/helpers/ecard_block.php +++ b/3.1/modules/ecard/helpers/ecard_block.php @@ -1,7 +1,7 @@ item() && $theme->item()->is_photo() && module::get_var("ecard", "location") == "sidebar") { $block = new Block(); - $block->css_id = "g-send-ecard"; + $block->css_id = "g-sendecard"; $block->title = t("eCard"); $block->content = new View("ecard_block.html"); } diff --git a/3.1/modules/ecard/helpers/ecard_event.php b/3.1/modules/ecard/helpers/ecard_event.php index 06165b8f..ebbd5442 100644 --- a/3.1/modules/ecard/helpers/ecard_event.php +++ b/3.1/modules/ecard/helpers/ecard_event.php @@ -1,7 +1,7 @@ css("ecard.css"); + return $theme->css("ecard.css"); } } \ No newline at end of file diff --git a/3.1/modules/ecard/module.info b/3.1/modules/ecard/module.info index 95c8f6a4..d5b27c70 100644 --- a/3.1/modules/ecard/module.info +++ b/3.1/modules/ecard/module.info @@ -1,4 +1,3 @@ name = "E-Card" description = "Send a photo as a postcard" -version = 4 - +version = 11 diff --git a/3.1/modules/ecard/views/ecard_block.html.php b/3.1/modules/ecard/views/ecard_block.html.php index 3f307a1d..d8aa4e4e 100644 --- a/3.1/modules/ecard/views/ecard_block.html.php +++ b/3.1/modules/ecard/views/ecard_block.html.php @@ -1,6 +1,6 @@ -id}") ?>" id="g-send-ecard" +id}") ?>" class="g-dialog-link g-button ui-state-default ui-corner-all"> - + diff --git a/3.1/modules/ecard/views/ecard_form.html.php b/3.1/modules/ecard/views/ecard_form.html.php new file mode 100644 index 00000000..fc22e95b --- /dev/null +++ b/3.1/modules/ecard/views/ecard_form.html.php @@ -0,0 +1 @@ + Send eCard \ No newline at end of file diff --git a/3.1/modules/editcreation/helpers/editcreation_event.php b/3.1/modules/editcreation/helpers/editcreation_event.php index c76e730d..8820d8fa 100644 --- a/3.1/modules/editcreation/helpers/editcreation_event.php +++ b/3.1/modules/editcreation/helpers/editcreation_event.php @@ -1,7 +1,7 @@ item(); if ( $item && access::can("edit", $item) ) { - $theme->css("editcreation.css"); + return $theme->css("editcreation.css"); } } } diff --git a/3.1/modules/embed_videos/controllers/embedded_videos.php b/3.1/modules/embed_videos/controllers/embedded_videos.php index 6c86e3a0..fc7281f2 100644 --- a/3.1/modules/embed_videos/controllers/embedded_videos.php +++ b/3.1/modules/embed_videos/controllers/embedded_videos.php @@ -1,7 +1,7 @@ order_by("exif_coordinates.latitude", "ASC") ->descendants(); $curr_album = ORM::factory("item")->where("id", "=", $type_id)->find_all(); - $map_title = $curr_album[0]->name; + $map_title = $curr_album[0]->title; } elseif ($map_type == "user") { // Generate an array of all items uploaded by the current user that // have exif gps coordinates and order by latitude (to group items diff --git a/3.1/modules/exif_gps/helpers/exif_gps.php b/3.1/modules/exif_gps/helpers/exif_gps.php index d3440424..823b4b29 100644 --- a/3.1/modules/exif_gps/helpers/exif_gps.php +++ b/3.1/modules/exif_gps/helpers/exif_gps.php @@ -1,7 +1,7 @@ get("completed"); // Generate an array of the next 100 photos to check. - $all_photos = ORM::factory("item") - ->where("id", ">", $last_id) - ->where("type", "=", "photo") - ->find_all(100); + //$all_photos = ORM::factory("item") + // ->where("id", ">", $last_id) + // ->where("type", "=", "photo") + // ->order_by("id") + // ->find_all(100); // Check each photo in the array to see if it already has exif gps data associated with it. // If it doesn't, attempt to extract gps coordinates. foreach (ORM::factory("item") ->where("id", ">", $last_id) ->where("type", "=", "photo") + ->order_by("id") ->find_all(100) as $item) { $record = ORM::factory("exif_coordinate")->where("item_id", "=", $item->id)->find(); diff --git a/3.1/modules/exif_gps/helpers/exif_gps_theme.php b/3.1/modules/exif_gps/helpers/exif_gps_theme.php index 160373a2..90431195 100644 --- a/3.1/modules/exif_gps/helpers/exif_gps_theme.php +++ b/3.1/modules/exif_gps/helpers/exif_gps_theme.php @@ -1,7 +1,7 @@ css("exif_gps_menu.css"); + return $theme->css("exif_gps_menu.css"); } } diff --git a/3.1/modules/exif_gps/models/exif_coordinate.php b/3.1/modules/exif_gps/models/exif_coordinate.php index 481da1cd..e3286d93 100644 --- a/3.1/modules/exif_gps/models/exif_coordinate.php +++ b/3.1/modules/exif_gps/models/exif_coordinate.php @@ -1,7 +1,7 @@ css("favourites.css"); - $theme->script("favourites.js"); + return $theme->css("favourites.css") + . $theme->script("favourites.js"); } static function header_top($theme) { diff --git a/3.1/modules/google_analytics/controllers/admin_google_analytics.php b/3.1/modules/google_analytics/controllers/admin_google_analytics.php index 84b7daeb..4a28ad8d 100644 --- a/3.1/modules/google_analytics/controllers/admin_google_analytics.php +++ b/3.1/modules/google_analytics/controllers/admin_google_analytics.php @@ -1,7 +1,7 @@ script("highroller.js"); - printf("", url::site("highroller/pick_theme")); + return $theme->script("highroller.js") + . sprintf("", url::site("highroller/pick_theme")); } static function header_top($theme) { diff --git a/3.1/modules/html_uploader/controllers/uploader.php b/3.1/modules/html_uploader/controllers/uploader.php index 78c64468..0b9b5351 100644 --- a/3.1/modules/html_uploader/controllers/uploader.php +++ b/3.1/modules/html_uploader/controllers/uploader.php @@ -1,7 +1,7 @@ script("kbd_nav.js"); - } -} \ No newline at end of file diff --git a/3.1/modules/kbd_nav/js/kbd_nav.js b/3.1/modules/kbd_nav/js/kbd_nav.js deleted file mode 100644 index 25eb7210..00000000 --- a/3.1/modules/kbd_nav/js/kbd_nav.js +++ /dev/null @@ -1,102 +0,0 @@ -/** -* -* Copyright (c) 2010 Serguei Dosyukov, http://blog.dragonsoft.us -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation -* files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, -* modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*/ - -$.fn.KbdNavigation = function(options, callback) { - - this.options = options || {}; - var opt = this.options; - this.callback = callback || null; - var clbk = this.callback; - - $(this).bind("keydown", function(event) { - if ($('#sb-body-inner>img#sb-content').is(':visible')) { - return false; - } - // ignore shortcuts when inside a jQuery dialog; otherwise it becomes impossible - // to navigate the cursor inside an input box - if ($('.ui-widget-overlay').is(':visible')) { - return true; - } - - var direction = "ltr"; - if (document.body) { - if (window.getComputedStyle) { - direction = window.getComputedStyle(document.body, null).direction; - } else if (document.body.currentStyle) { - direction = document.body.currentStyle.direction; - } - } - - var lnk = ""; - var lnk_first, lnk_prev, lnk_parent, lnk_next, lnk_last; - - if(opt.first) { lnk_first = opt.first; } else { lnk_first = $("#g-navi-first").attr("href"); } - if(opt.prev) { lnk_prev = opt.prev; } else { lnk_prev = $("#g-navi-prev").attr("href"); } - if(opt.parent) { lnk_parent = opt.parent; } else { lnk_parent = $("#g-navi-parent").attr("href"); } - if(opt.next) { lnk_next = opt.next; } else { lnk_next = $("#g-navi-next").attr("href"); } - if(opt.last) { lnk_last = opt.last; } else { lnk_last = $("#g-navi-last").attr("href"); } - - // Support for standard Wind Theme tags - if(!lnk_first) { lnk_first = $(".g-paginator .ui-icon-seek-first").parent().attr("href"); } - if(!lnk_prev) { lnk_prev = $(".g-paginator .ui-icon-seek-prev").parent().attr("href"); } - if(!lnk_next) { lnk_next = $(".g-paginator .ui-icon-seek-next").parent().attr("href"); } - if(!lnk_last) { lnk_last = $(".g-paginator .ui-icon-seek-end").parent().attr("href"); } - - var keyCode = event.keyCode; - - if (direction == "rtl") { - switch(keyCode) { - case 0x25: // Left - keyCode = 0x27; - break; - case 0x27: // Right - keyCode = 0x25; - break; - } - } - - switch(keyCode) { - case 0x25: // Ctr+Left/Left - if(event.ctrlKey) { lnk = lnk_first; } else { lnk = lnk_prev; } - break; - case 0x26: // Ctrl+Up - if(event.ctrlKey) { lnk = lnk_parent; } - break; - case 0x27: // Ctrl+Right/Right - if(event.ctrlKey) { lnk = lnk_last; } else { lnk = lnk_next; } - break; - } - - if(lnk) { - if(typeof clbk == 'function') { - clbk(); - return false; - } else { - window.location = lnk; - return true; - } - } - - return true; - }); -} - -$(document).ready( function() { - $(document).KbdNavigation({}); - if ($('#sb-content').is(':visible')) { return true; } -}); diff --git a/3.1/modules/kbd_nav/module.info b/3.1/modules/kbd_nav/module.info deleted file mode 100644 index 2eda7c73..00000000 --- a/3.1/modules/kbd_nav/module.info +++ /dev/null @@ -1,3 +0,0 @@ -name = "Kbd Navigation" -description = "Adds keyboard navigation to the gallery.
      Version 1.5 | By Serguei Dosyukov | Visit plugin Site | Support" -version = 5 diff --git a/3.1/modules/keeporiginal/controllers/keeporiginal.php b/3.1/modules/keeporiginal/controllers/keeporiginal.php index 0bb3aa4f..36f6affe 100644 --- a/3.1/modules/keeporiginal/controllers/keeporiginal.php +++ b/3.1/modules/keeporiginal/controllers/keeporiginal.php @@ -1,7 +1,7 @@ css("language_flags_sidebar.css"); + return $theme->css("language_flags_sidebar.css"); } } diff --git a/3.1/modules/latestalbums/helpers/latestalbums_rss.php b/3.1/modules/latestalbums/helpers/latestalbums_rss.php index 8aca12a7..aa34088c 100644 --- a/3.1/modules/latestalbums/helpers/latestalbums_rss.php +++ b/3.1/modules/latestalbums/helpers/latestalbums_rss.php @@ -1,7 +1,7 @@ "ldap", "allow_updates" => false, "params" => array( - "groups" => array("eng", "google", "guest"), + "groups" => array("engineering", "everybody", "guest"), "everybody_group" => "guest", - "registered_users_group" => "google", - "admins" => array("mediratta", "martinm"), - "url" => "ldaps://ldap.corp.google.com/", - "group_domain" => "ou=Posix,ou=Groups,dc=google,dc=com", - "user_domain" => "ou=People,dc=google,dc=com", + "registered_users_group" => "everybody", + "admins" => array("alice", "bob"), + "url" => "ldaps://ldap.mycompany.com/", + "group_domain" => "ou=Posix,ou=Groups,dc=ymcompany,dc=com", + "user_domain" => "ou=People,dc=MyCompany,dc=com", "bind_rdn" => null, "bind_password" => null, ) diff --git a/3.1/modules/ldap/helpers/ldap_installer.php b/3.1/modules/ldap/helpers/ldap_installer.php index 37269748..d9bdbfd4 100644 --- a/3.1/modules/ldap/helpers/ldap_installer.php +++ b/3.1/modules/ldap/helpers/ldap_installer.php @@ -1,7 +1,7 @@ get("add_menu"); - if (!empty($submenu)) { - $item = $submenu->get("add_photos_item"); - if (!empty($item)) { $item->css_class("ui-icon-plus"); } - - $item = $submenu->get("add_album_item"); - if (!empty($item)) { $item->css_class("ui-icon-note"); } - } - - $submenu = $menu->get("options_menu"); - if (!empty($submenu)) { - $item = $submenu->get("edit_item"); - if (!empty($item)) { $item->css_class("ui-icon-pencil"); } - - $item = $submenu->get("edit_permissions"); - if (!empty($item)) { $item->css_class("ui-icon-key"); } +class max_size_event_Core { + static function item_before_create($item) { + $max_size = module::get_var("max_size", "max_size", 600); + if ($item->is_photo()) { + list ($width, $height, $mime_type) = photo::get_file_metadata($item->data_file); + if ($width > $max_size || $height > $max_size) { + $tempnam = tempnam(TMPPATH, "size"); + $tmpfile = $tempnam . "." . pathinfo($item->data_file, PATHINFO_EXTENSION); + gallery_graphics::resize( + $item->data_file, $tmpfile, + array("width" => $max_size, "height" => $max_size, "master" => Image::AUTO)); + rename($tmpfile, $item->data_file); + unlink($tempnam); + } } } -} +} \ No newline at end of file diff --git a/3.1/modules/max_size/helpers/max_size_installer.php b/3.1/modules/max_size/helpers/max_size_installer.php new file mode 100644 index 00000000..1a7f2be9 --- /dev/null +++ b/3.1/modules/max_size/helpers/max_size_installer.php @@ -0,0 +1,25 @@ +page_title = t("Gallery 3 :: Manage Module Updates"); $view->content = new View("admin_moduleupdates.html"); + $view->content->mu_version = module::get_version("moduleupdates"); - $devDebug = false; - $refreshCache = false; + $refreshCache = false; $cache = unserialize(Cache::instance()->get("moduleupdates_cache")); - $cache_updates = unserialize(Cache::instance()->get("moduleupdates_cache_updates")); - - //--------------------------------------------------------------------------------------------- - //echo 'Message 01: ' .$cache_updates . '
      '; - //--------------------------------------------------------------------------------------------- + $cache_updates = unserialize(Cache::instance()->get("moduleupdates_cache_updates")); //if someone pressed the button to refresh now if (request::method() == "post") { @@ -78,7 +73,6 @@ class Admin_Moduleupdates_Controller extends Admin_Controller { } } catch (Exception $e) { - //echo 'Message: ' .$e->getMessage() . '
      '; } //Check the ability to access the Google $Google = null; @@ -91,71 +85,82 @@ class Admin_Moduleupdates_Controller extends Admin_Controller { } } catch (Exception $e) { - //echo 'Message: ' .$e->getMessage() . '
      '; } + $update_count = 0; + if($refreshCache == true){ foreach (module::available() as $this_module_name => $module_info) { + + $font_color_local = "black"; + $core_version = ''; + $core_server = ''; + $core_dlink = ''; + $font_color_core = "black"; + $contrib_version = ''; + $contrib_server = ''; + $contrib_dlink = ''; + $font_color_contrib = "black"; + $gh_version = ''; + $gh_server = ''; + $gh_dlink = ''; + $font_color_gh = "black"; - //example code for setting cache values - //Cache::instance()->set($key, "$log{$msg}", array("task", "log", "import"), 2592000); - //example delete cache - //Cache::instance()->delete("update_l10n_cache:{$task->id}"); - //example for reading cache - //$log = Cache::instance()->get($key); - $remote_version = ''; - $remote_server = ''; - $update_count = 0; - list ($remote_version, $remote_server) = $this->get_remote_module_version($this_module_name, $devDebug); + $font_color_local = $this->get_local_module_version_color ($module_info->version, $module_info->code_version); + list ($core_version, $core_server) = $this->get_remote_module_version($this_module_name, "CORE"); + $font_color_core = $this->get_module_version_color ($module_info->version, $module_info->code_version, $core_version); + list ($contrib_version, $contrib_server) = $this->get_remote_module_version($this_module_name, "CONTRIB"); + $font_color_contrib = $this->get_module_version_color ($module_info->version, $module_info->code_version, $contrib_version); + list ($gh_version, $gh_server) = $this->get_remote_module_version($this_module_name, "GH"); + $font_color_gh = $this->get_module_version_color ($module_info->version, $module_info->code_version, $gh_version); - $font_color = "black"; - //BLUE - DNE: Does Not Exist, this module was not found - if ($remote_version == "DNE") { - $font_color = "blue"; - //PINK - Your installed version is newer than file version - } else if ($module_info->version != '' and $module_info->code_version < $module_info->version) { - $font_color = "pink"; - //ORANGE - Your file version is newer than the installed version - } else if ($module_info->version != '' and $module_info->code_version > $module_info->version) { - $font_color = "orange"; - //GREEN - Your version is newer than the GitHub - } else if ($remote_version < $module_info->code_version or ($module_info->version != '' - and $remote_version < $module_info->version)) { - $font_color = "green"; - //RED - Your version is older than the GitHub - } else if ($remote_version > $module_info->code_version or ($module_info->version != '' - and $remote_version > $module_info->version)) { - $font_color = "red"; + if($font_color_core == "red" or $font_color_contrib == "red" or $font_color_gh == "red"){ $update_count++; - /* - if($remote_server == "(G3)"){ - $module_info->name = "".$module_info->name.""; - }else if($remote_server == "(G3CC)"){ - $module_info->name = "".$module_info->name.""; - }else if($remote_server == "(brentil)"){ - $module_info->name = "".$module_info->name.""; - } - */ } $module_info->name = "".$module_info->name.""; + if (is_numeric($core_version)) { + if($core_version > $module_info->version) { + $core_dlink = "http://github.com/gallery/gallery3/tree/master/modules/".$this_module_name; + } + } + + if (is_numeric($contrib_version)) { + if($contrib_version > $module_info->version) { + $contrib_dlink = "http://github.com/gallery/gallery3-contrib/tree/master/". + substr_replace(gallery::VERSION,"",strpos(gallery::VERSION," ")) ."/modules/".$this_module_name; + } + } + + if (is_numeric($gh_version)) { + if($gh_version > $module_info->version) { + $this_gm_repo = str_replace(".","",substr_replace(gallery::VERSION,"",strpos(gallery::VERSION," "))); + if($this_gm_repo == "30"){ + $gh_dlink = "http://www.gallerymodules.com/update/".$this_module_name; + } else { + $gh_dlink = "http://www.gallerymodules.com/update".$this_gm_repo."/".$this_module_name; + } + + } + } + //populate the list fo modules and their data $cache->$this_module_name = array ("name" => $module_info->name, "locked" => $module_info->locked, "code_version" => $module_info->code_version, "active" => $module_info->active, "version" => $module_info->version,"description" => $module_info->description, - "remote_version" => $remote_version, "remote_server" => $remote_server, "font_color" => $font_color); + "core_version" => $core_version, "core_server" => $core_server, "font_color_core" => $font_color_core, + "contrib_version" => $contrib_version, "contrib_server" => $contrib_server, "font_color_contrib" => $font_color_contrib, + "gh_version" => $gh_version, "gh_server" => $gh_server, "font_color_gh" => $font_color_gh, + "font_color_local" => $font_color_local, "core_dlink" => $core_dlink, "contrib_dlink" => $contrib_dlink, + "gh_dlink" => $gh_dlink); } //Define right now as YYYY.MM.DD HH:MM with the # of updates that are out of date $cache_updates = array("date" => date("Y.m.d - H:i"), "updates" => $update_count); - - //--------------------------------------------------------------------------------------------- - //echo 'Message 02: ' .$cache_updates . '
      '; - //--------------------------------------------------------------------------------------------- - + //Write out the new data to cache with a 30 day expiration & 0 for update data so it's always present Cache::instance()->set("moduleupdates_cache", serialize($cache), array("ModuleUpdates"), 30*86400); Cache::instance()->set("moduleupdates_cache_updates", serialize($cache_updates), array("ModuleUpdates"), null); @@ -167,12 +172,59 @@ class Admin_Moduleupdates_Controller extends Admin_Controller { $view->content->csrf = access::csrf_token(); $view->content->Google = $Google; $view->content->GitHub = $GitHub; + $view->content->Gallery_Version = substr_replace(gallery::VERSION,"",strpos(gallery::VERSION," ")); print $view; } + /** + * + **/ + private function get_module_version_color ($version, $code_version, $remote_version) { + + $font_color = "black"; + + //BLACK - no module version detected + if ($remote_version == "") { + $font_color = "black"; + //BLUE - DNE: Does Not Exist, this module was not found + } else if ($remote_version == "DNE") { + $font_color = "blue"; + //GREEN - Your version is newer than the GitHub + } else if ($remote_version < $code_version or ($version != '' + and $remote_version < $version)) { + $font_color = "green"; + //RED - Your version is older than the GitHub + } else if ($remote_version > $code_version or ($version != '' + and $remote_version > $version)) { + $font_color = "red"; + } + + return $font_color; + } + + + /** + * + **/ + private function get_local_module_version_color ($version, $code_version) { + + $font_color = "black"; + + //PINK - Your installed version is newer than file version + if ($version != '' and $code_version < $version) { + $font_color = "pink"; + //ORANGE - Your file version is newer than the installed version + } else if ($version != '' and $code_version > $version) { + $font_color = "orange"; + } + + return $font_color; + } + + /** * Parses the known GitHub repositories for new versions of modules. * @@ -182,71 +234,88 @@ class Admin_Moduleupdates_Controller extends Admin_Controller { * * http://github.com/gallery/gallery3 * http://github.com/gallery/gallery3-contrib + * http://www.gallerymodules.com * * @author brentil - * @param String The folder name of the module to search for on the remote GitHub server - * @return Array An array with the remote module version and the server it was found on. + * @param String - The folder name of the module to search for on the remote GitHub server + * @param String - The remote server to check against + * @return Array - An array with the remote module version and the server it was found on. */ - private function get_remote_module_version ($module_name, $devDebug) { + private function get_remote_module_version ($module_name, $server_location) { - $version = 'DNE'; + $version = ''; $server = ''; $file = null; - //For development debug only - if ($devDebug == true){ - if ($file == null) { - try { - $file = fopen ("http://github.com/brentil/gallery3-contrib/raw/master/3.1/modules/".$module_name."/module.info", "r"); - if ($file != null) { - $server = '(brentil)'; + switch ($server_location) { + case "CONTRIB": + //Check the Gallery3 Community Contributions GitHub + if ($file == null) { + try { + $file = fopen ("http://github.com/gallery/gallery3-contrib/raw/master/". + substr_replace(gallery::VERSION,"",strpos(gallery::VERSION," "))."/modules/".$module_name."/module.info", "r"); + if ($file != null) { + $server = '(GCC)'; + } + } + catch (Exception $e) { + } } - } - catch (Exception $e) { - //echo 'Message: ' .$e->getMessage() . '
      '; - } - } - } - - //Check the main Gallery3 GitHub - if ($file == null) { - try { - $file = fopen ("http://github.com/gallery/gallery3/raw/master/modules/".$module_name."/module.info", "r"); - if ($file != null) { - $server = '(G3)'; - } - } - catch (Exception $e) { - //echo 'Message: ' .$e->getMessage() . '
      '; - } + break; + case "CORE": + //Check the main Gallery3 GitHub + if ($file == null) { + try { + $file = fopen ("http://github.com/gallery/gallery3/raw/master/modules/".$module_name."/module.info", "r"); + if ($file != null) { + $server = '(G)'; + } + } + catch (Exception $e) { + } + } + break; + case "GH": + //Check GalleryModules.com + if ($file == null) { + try { + $this_gm_repo = str_replace(".","",substr_replace(gallery::VERSION,"",strpos(gallery::VERSION," "))); + if($this_gm_repo == "30"){ + $file = fopen ("http://www.gallerymodules.com/m/".$module_name, "r"); + } else { + $file = fopen ("http://www.gallerymodules.com/".$this_gm_repo."m/".$module_name, "r"); + } + if ($file != null) { + $server = '(GH)'; + } + } + catch (Exception $e) { + } + } + break; } - - //Check the Gallery3 Community Contributions GitHub - if ($file == null) { - try { - $file = fopen ("http://github.com/gallery/gallery3-contrib/raw/master/3.1/modules/".$module_name."/module.info", "r"); - if ($file != null) { - $server = '(G3CC)'; - } - } - catch (Exception $e) { - //echo 'Message: ' .$e->getMessage() . '
      '; - } - } - - if ($file != null) { + + if ($file != null) { while (!feof ($file)) { $line = fgets ($file, 1024); - - //Regular expression to find & gather the version number in the remote module.info file - if (preg_match ("@version = (.*)@i", $line, $out)) { - $version = $out[1]; - break; - } + if ($server_location == "GH"){ + //GH stores only the version info + if($line == "Not entered" or $line == "See git") { + $line = ""; + } + $version = $line; + break; + } else { + //Regular expression to find & gather the version number in the remote module.info file + if (preg_match ("@version = (.*)@i", $line, $out)) { + $version = $out[1]; + break; + } + } } fclose ($file); } - return array ($version, $server); - } -} + return array ($version, $server); + } +} \ No newline at end of file diff --git a/3.1/modules/moduleupdates/helpers/moduleupdates_event.php b/3.1/modules/moduleupdates/helpers/moduleupdates_event.php index dd6efc9c..ebafb880 100644 --- a/3.1/modules/moduleupdates/helpers/moduleupdates_event.php +++ b/3.1/modules/moduleupdates/helpers/moduleupdates_event.php @@ -1,6 +1,6 @@ delete("ModuleUpdates"); //create the blank ModuleUpdates cache entry with an expiration of 0 days @@ -34,7 +34,7 @@ class moduleupdates_installer { } static function upgrade($version) { - module::set_version("moduleupdates", 2); + module::set_version("moduleupdates", 7); //Remove the ModuleUpdates cache entry 'JIC' Cache::instance()->delete("ModuleUpdates"); //Empty the ModuleUpdates cache entry so our new version starts from scratch @@ -48,4 +48,4 @@ class moduleupdates_installer { Cache::instance()->delete("ModuleUpdates"); module::delete("moduleupdates"); } -} +} \ No newline at end of file diff --git a/3.1/modules/moduleupdates/module.info b/3.1/modules/moduleupdates/module.info index cf43770b..bbf3516a 100755 --- a/3.1/modules/moduleupdates/module.info +++ b/3.1/modules/moduleupdates/module.info @@ -1,3 +1,3 @@ name = "Module Updates" description = "Compares your installed module version against the ones stored in the GitHub." -version = 3 +version = 7 \ No newline at end of file diff --git a/3.1/modules/moduleupdates/views/admin_moduleupdates.html.php b/3.1/modules/moduleupdates/views/admin_moduleupdates.html.php index 3fdc06a7..e55ed7af 100644 --- a/3.1/modules/moduleupdates/views/admin_moduleupdates.html.php +++ b/3.1/modules/moduleupdates/views/admin_moduleupdates.html.php @@ -2,8 +2,8 @@
      -

      - +

      +
      @@ -16,7 +16,6 @@
    • Green = Your version is newer than the GitHub
      ") ?>
    • Orange = Your file version is newer than the installed version
      ") ?>
    • Pink = Your installed version is newer than file version
      ") ?>
    • -
    • Blue = Does Not Exist/No information available
      ") ?>
    • ") ?>
    • " class="submit" />
    @@ -25,24 +24,51 @@
      -
    • +
    - - - - - - - - - - "> - - - - - - -
    [File/Installed]") ?>
    "; ?> "; ?> "; ?> "; ?>
    +
    + Core Modules + + + + + + + + + + "> + + + + + + + +
    Installed") ?>
    "; ?> *"; } ?> "; } ?> "; ?> *"; } ?> $module_name['code_version']) { echo "".$module_name['core_version']."";} else { echo $module_name['core_version']; } ?> "; } ?>
    +
    +
    + Community Contributed Modules + + + + + + + + + + + "> + + + + + + + + +
    Installed") ?>
    "; ?> *"; } ?> "; } ?> "; ?> *"; } ?> $module_name['version'] or $module_name['core_version'] > $module_name['code_version']) { echo "".$module_name['contrib_version']."";} else { echo $module_name['contrib_version']; } ?> "; } ?> "; ?> *"; } ?> $module_name['version'] or $module_name['core_version'] > $module_name['code_version']) { echo "".$module_name['gh_version']."";} else { echo $module_name['gh_version']; } ?> "; } ?>
    +
    \ No newline at end of file diff --git a/3.1/modules/navcarousel/controllers/navcarousel.php b/3.1/modules/navcarousel/controllers/navcarousel.php index 7b8125a7..3b5401a7 100644 --- a/3.1/modules/navcarousel/controllers/navcarousel.php +++ b/3.1/modules/navcarousel/controllers/navcarousel.php @@ -1,7 +1,7 @@ script("jquery.jcarousel.min.js"); - $theme->css("skin.css"); $showelements = module::get_var("navcarousel", "showelements", "7"); $childcount = $theme->item->parent()->viewable()->children_count(); $itemoffset = intval(floor($showelements / 2)); @@ -64,7 +62,10 @@ class navcarousel_theme_Core { $onwinload = "});\n $(window).load(function () {\n"; } - Return "\n + return + $theme->script("jquery.jcarousel.min.js") + . $theme->css("skin.css") + . "\n - - -
    -
    -
    -
    - -
    -
    - -
    -
    - -
    -
    diff --git a/3.1/themes/greydragon/changelog.txt b/3.1/themes/greydragon/changelog.txt deleted file mode 100644 index 3d5a1451..00000000 --- a/3.1/themes/greydragon/changelog.txt +++ /dev/null @@ -1,239 +0,0 @@ -=== Grey Dragon Theme === -Grey Dragon Theme - a custom theme for Gallery 3 - -This theme was designed and built by Serguei Dosyukov, whose blog you will find at http://blog.dragonsoft.us/ -Copyright (C) 2009-2010 Serguei Dosyukov - -Tested up to: G3 3.0 RC2 (Santa Fe) Experimental -Minimum requirement: G3 3.0 RC2 (Santa Fe) Experimental -Donate link: http://blog.dragonsoft.us/gallery-3/ - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street Fifth Floor, Boston, MA 02110-1301, USA. - -=== Open issues === -- Issue with Delete functionality -- Support for new organize module -- Support for Register module -- Issue with Comments module - -=== Changelog === - -version 2.3.1 -- Hide Rotate operations for pictures since they are not supported by the theme -- Added use of common gallery.ajax.js. Fix issue with some Ajax based links. -- Layout fixes for Translation form overlay -- Changed CSS styling for buttons to provide unified coverage for buttons and links exposed as buttons. -- ADMIN: Fixed options group styles in Theme's Admin panel -- ADMIN: Advanced Settings for Thumbs and Individual Photo are moved into separate sections. -- ADMIN: New option - display meta data in Photo description section -- ADMIN: New option/fix - SEO indexing is now allowed by default. In order to prevent your site from being indexed, you can now use "Disallow Search Engine Indexing" option - -version 2.3.0 -- Adopted for Gallery 3.0RC2 changes (minor template adjustments, css class name changes, etc.) - -version 2.2.1 -- Redesigned Ready event handler for the theme to ensure proper ShadowBox initialization -- Added support for gallery_dialog() function call used by some 3rd party modules - some sync issues are solved by imposed delay of 1 second -- GPS module - better action list alignment in the sidebar - -version 2.2.0 -- Added support for slideshow mode in Photo Preview -- Fixed issue with Info side block - missing markup -- Fixed issue with Upload dialog layout with some resolutions/fonts -- ADMIN: Added option to hide breadcrumbs -- ADMIN: Added prerequisite check for Info module - required for Thumb meta data display - -version 2.1.7 -- Added support for missing images in the thumbs to allow proper operations with empty albums or albums with broken thumbs -- Some color optimizations -- Color improvements for "Add Image" dialog -- Better support for Basket module - -version 2.1.6 -- Wind colorpack adjusted to closer match default Wind theme - -version 2.1.5 -- Minor changes in ADMIN infrastructure -- ADMIN: added check for Kbd Navigation module -- ADMIN: New color pack - carbon - -version 2.1.4 -- Minor refactoring in paginator -- Added support for keyboard navigation module (http://codex.gallery2.org/Gallery3:Modules:kbd_nav) - -version 2.1.3 -- Sidebar restricted to item related pages (album, photo, movie, etc) -- Fixed issue with bottom border not applied to all instances of H1 tag -- Min footer size set to 4em -- ADMIN: "Photo: Description Display Mode" option added -- ADMIN: Added new maintenance operation - "Reset Exif Info" - -version 2.1.2 -- Fixed issue with Album thumbs - empty space under -- Thumb Item's Title Display Mode expanded to be applied to Item's description in Photo page -- More documentations in CSS files, some movements -- Some cleanup for Wind color pack -- Fixed font name typo in screen.css -- Fixed "Waiting" roller for Wind theme to match background -- Added "up" button in navigation - -version 2.1.1 -- Increased size of Add photo dialog for better display on some lower resolutions. -- ADMIN: New option: "Thumb: Item's Title Display Mode" - specifies how to display item's title in thumbs : Overlay Bottom Hide - -version 2.1.0 -- Custom Info Block to include item's description -- Image is centered when "Actual Size" aspect is used for thumbs -- Added support for color packs - included: greydragon, wind -- ADMIN: Improved error handling -- ADMIN: Disable submit button on click to prevent Dbl-click -- ADMIN: New option: Enable page cache - adds header marker for page to be cached for 60 seconds - -version 2.0.1 -- Enable BBCode/HTML support in individual photo descriptions -- Fixed main menu overlay issue when in top position -- Theme's credits moved into dedicated method -- CSS clean up -- Comments module layout enhancements - -version 2.0.0 -- Major redesign of the gallery flow. - - Added caption and metadata (Admin/optional) overlay for thumbs. - - Added description overlay in individual Photo view (look for "Learn More" marker). - - Based on Admin setting, thumbs are adjusted to fit Digital/Film/Actual size. -- Attempt to fix issue with JS load latency to prevent unhandled AJAX calls -- Added code protection for theme initialization procedure -- ADMIN: Thumb Aspect Ratio option. See help section for more info. - -version 1.8.2 -- Increased based font size -- Layout adjusted to match new settings -- ADMIN: New option - Place Login Link in the Header - -version 1.8.1 -- ADMIN: small adjustments in layout and help info -- 3rd party module's related CSS moved into contrib.css -- Adjust user profile screen to match new layout -- initial design for calendar module - -version 1.8.0 -- ADMIN: Major redesign of the layout. Help section added. -- ADMIN: New option - Show main menu for guest user -- Minimum required Gallery version set to 30 -- When configured not to use sidebar, theme is switched into 4 columns layout - -version 1.7.6 -- Organize module: CSS improvements -- Fixed issue with Chrome browser - -version 1.7.5 -- ADMIN: Added option to reset theme to default state -- CSS: some size adjustments for dialogs. Added minimum height for overlay to keep dialogs from shrinking. - -version 1.7.4 -- ADMIN: Theme Gallery 3 core requirement changed to v.26 -- ADMIN: Most of theme's settings are documented using element's title attribute - hover over to see a description -- Edit Permissions form redesigned and enlarged to fit more information - -version 1.7.3 -- ADMIN: Default states for the theme options are no longer being stored. Please save theme settings at least once to take advantage of a new functionality. -- Photo Navigator default position is set to Top Only - -version 1.7.2 -- Fix in Uploader dialog to keep items inside respected boxes -- Organize module support has been abandoned. Please use GWT Organize module instead. Added item in Prerequisites Checklist. - -version 1.7.1 -- CSS: Fixed visibility of the "Select Photo" button in "Add photo" dialog -- CSS: Fixed "ghost" line for navigation buttons when zoomed-in in IE -- Admin: fixed issue with prerequisite check not detecting deleted modules -- /views/support folder deprecated. Logic moved into Theme_View extension class for Theme_View_Core -- Theme Options Page management, generic Page code and BBCode processor moved into Theme_View class -- HACK: Info block is not displayed if there is no description for the item - -version 1.6.4 -- Admin: Added "Show Sidebar for Albums only" option -- Admin: added error visibility to the requirements validation list -- Small CSS adjustments: Fixed footer min size issue when no site credit info is displayed; added space between Credits in the footer and Footer text area. -- Few missing parts from last git sync - -version 1.6.3 -- Kohana 2.4 support -- Support for Movie files view -- Admin: Allow hide Sidebar Block header - -version 1.6.2 -- Admin: Page navigator option changed to use combobox -- Admin: Added option to hide item description in albums - -version 1.6.2 -- Small CSS adjustments. -- All operation dialogs should be visible now -- Context menu: "Rotate 90..." items are removed due to an issue with image quality affected by the operation -- Context menu: "Choose as the album cover" is now properly handled - -version 1.6.1 -- Admin: When allowed sidebar position is "Default Only", don't disregard selected Default position -- Adjust item's toolbar buttons to align properly when side bar position is fixed -- BBCode parser improved to support stripping of BBCode for Page title and breadcrumbs -- Fixed issue with main menu missing class declaration not allowing open dialogs -- Adjust context dialogs to properly show caption info -- Caption added to Full size Preview -- "New Comment" form styled -- Admin: Option to align main menu to the top and Breadcrumbs to the left - -version 1.6.0 -- Admin: Fixed issue with "Rebuild thumbs" option in theme admin -- Admin: Fixed issue with Item's toolbar not properly aligned in Quirks Mode -- Exif data dialog Layout changes -- Item context menu improvements: - - Fixed issue with submit logic - - Layout fixes for context menu dialogs - -version 1.5.8 -- Admin: First release of the Theme admin option. After theme installation, visit Appearance/Theme - Options to configure the theme. If you had older version of the theme, initial setup is also required. - The following settings are available: - - Rows per album page - theme uses 3 columns layout for pictures, therefore default page_size is computed in x3 increments - - Thumb size is restricted to 200 and therefore not available for administration - - Mark to build resizes/thumbs - allows force rebuilding of images - - Show/Hide top/bottom photo navigators - - Specify allowed and default sidebar position - - Administrator can now specify Copyright message to display in the footer - - Site logo is now default to Gallery 3 logo, but admin can provide a path to custom logo. - - Admin module validates Theme's requirements (Shadowbox module need to be installed/active) -- Sidebar session cookie is set to expire in 365 days - -version 1.5.7 -- Status message has been moved into header as popup to prevent obstruction of the main view. - jQuery is used to fade it out in 10 sec. -- Improved logic for dialogs on submit -- Theme related JS has been moved out of the page.html.php - -version 1.5.6 -- Fixed issue with tollbar buttons not properly aligned/shown when page is resized. -- Copyright info moved into DB. To change default settings add [th_greydragon/copyright] into VARS table. - -version 1.5.5 -- CSS fixes. -- Theme adjusted to be compatible with latest Git. -- Login links are moved into footer. -- Pagination module redesigned to support new structure of paging data. - -version 1.5.4 -- CSS fixes. -- Added support for Comments block. -- Improved support for Modal dialogs. - -version 1.5.3 -- Updated to match latest git. -- Exif menu customization is now part of the theme. -- Sidebar management button is disabled for current mode. - -version 1.5.2 -- Code, layout, css cleanup. -- New thumbs for buttons. -- First set of Ajax dialogs is ready and now operational: Login, user info, edit album, exit info. -- Fixed some browser related issues. \ No newline at end of file diff --git a/3.1/themes/greydragon/controllers/greydragon.php b/3.1/themes/greydragon/controllers/greydragon.php deleted file mode 100644 index 0796d801..00000000 --- a/3.1/themes/greydragon/controllers/greydragon.php +++ /dev/null @@ -1,39 +0,0 @@ -page_title = t("%name Profile", array("name" => $user->display_name())); - $v->content = new View("user_profile.html"); - - $v->content->user = $user; - $v->content->contactable = - !$user->guest && $user->id != identity::active_user()->id && $user->email; - $v->content->editable = - identity::is_writable() && !$user->guest && $user->id == identity::active_user()->id; - - $event_data = (object)array("user" => $user, "content" => array()); - module::event("show_user_profile", $event_data); - $v->content->info_parts = $event_data->content; - - print $v; - } -*/ -} diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/colors.css b/3.1/themes/greydragon/css/colorpacks/carbon/colors.css deleted file mode 100644 index 57fd30dd..00000000 --- a/3.1/themes/greydragon/css/colorpacks/carbon/colors.css +++ /dev/null @@ -1,192 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * ColorPack: Carbon - Default color pack - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* styles.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -html { background-color: #333; } -body { color: #999; background-color: #333; } - -h1 { border-bottom: #6f6f6f 1px solid; } -a { color: #999 !important; font-weight: bold; } -.ui-icon { background-image: url(images/ui-icons.png); } - -/* styles.css - Header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-header .g-message-block { border: 1px #888 solid; background-color: #AAA; color: #000; } -.g-breadcrumbs li { background: transparent url(images/ico-separator.png) no-repeat 0 0.2em; } - -/* styles.css - Content ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-main { background-color: #3f3f3f; margin-left: 10px; margin-right: 10px; } - -/* styles.css - Footer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -/* styles.css - Album Layout ~~~~~~~~~~~~~~~~~~~~~~~~~*/ -#g-info .g-description { border: #6f6f6f 1px solid; } - -.g-thumbslide, .g-thumbslide-ext { border: 1px solid #303E43; background-color: #555; } -.g-thumbcrop { border: 1px solid #303E43; } - -.g-album .g-thumbslide, -.g-album .g-thumbslide-ext { border-top: 1px solid #6f6f6f; border-left: 1px solid #6f6f6f; border-right: 4px double #6f6f6f; border-bottom: 4px double #6f6f6f; } -.g-photo .g-thumbslide, /* Need to compensate for double border in album's thumbs */ -.g-photo .g-thumbslide-ext { margin-bottom: 3px; } - -.g-thumbslide:hover .g-description { color: #fff; border-bottom: 1px solid #999; background: #1E1E1E; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } -.g-album .g-thumbslide:hover .g-description, -.g-album .g-thumbslide-ext .g-description { background: #555 url(images/ico-album.png) no-repeat 4px 2px; } - -.g-thumbslide:hover .g-metadata, -.g-thumbslide-ext:hover .g-metadata { border-top: 1px solid #999; background: #1E1E1E; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } - -/* styles.css - Photo Layout ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -div.g-resize { border: 1px solid #888; background: #555; } - -div.g-resize:hover .g-description { color: #fff; background: #1E1E1E; border-bottom: 1px solid #999; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } -div.g-resize .g-more { border: 1px solid #999; background: #1E1E1E; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } - -.g-movie { border: 1px solid #888; padding: 5px; background: #555; } - -/* styles.css - Reauthentificate ~~~~~~~~~~~~~~~~~~~~~*/ - -#g-reauthenticate-form ul { border: 1px #888 solid; } - -/* styles.css - Sidebar Blocks ~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-toolbar { border-bottom: 1px solid #737373; } - -/* styles.css - Sidebar Blocks : Common ~~~~~~~~~~~~~~*/ - -.g-block { border: 1px solid #737373; } -.g-block h2 { background: url(images/section.png) repeat-x; } - -/* styles.css - Sidebar Blocks : Buttons ~~~~~~~~~~~~~*/ - -#g-viewformat .g-viewthumb-left { background: url('images/view-left.png') no-repeat left top; } -#g-viewformat .g-viewthumb-right { background: url('images/view-right.png') no-repeat left top; } -#g-viewformat .g-viewthumb-full { background: url('images/view-full.png') no-repeat left top; } - -#g-slideshow-link { background: url("images/view-slideshow.png") top left no-repeat; } -.g-fullsize-link { background: url("images/view-fullsize.png") top left no-repeat; } -#g-exifdata-link { background: url("images/view-info.png") top left no-repeat; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* menus.css ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-site-menu ul { border: #000000 0 solid; } -#g-site-menu li a:hover { color: #000000; background-color: #333; } -#g-site-menu li:hover, -#g-site-menu li.iemhover { border: #303030 1px solid; background-color: #333; border-bottom: #000000 1px solid; } -#g-site-menu li ul { border: #000000 1px solid; } -#g-site-menu li ul li { border: #C0C0C0 0px solid; background-color: #333; } -#g-site-menu li ul li:hover, -#g-site-menu li ul li.iemhover { border: #C0C0C0 0 solid; background-color: #ddf2ff; } - -.g-item .g-context-menu { background-image: url(images/ui-icons.png); } -.g-item .g-context-menu:hover { background: #333 none; border: 1px #888 solid; } -.g-item .g-context-menu li li a:hover { background-color: #ddf2ff; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* forms.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-body { background: #101415 url('images/ajax-loading.gif') no-repeat center center; } -#sb-title { border-left: #303030 1px solid; border-right: #303030 1px solid; background-color: #333; } - -#sb-content.html_ajax p.g-error { color: red; } -#sb-content.html_ajax form { background-color: #101415; } -#sb-content.html_ajax>div { background-color: #101415; } - -/* forms.css - Permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-permissions .g-breadcrumbs { border: #303030 1px solid; } -#sb-content #g-edit-permissions-form { border: #303030 1px solid; } -#sb-content #g-move>ul { border: #303030 1px solid; } - -/* forms.css - Add item ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-add-photos-form .g-breadcrumbs { border: #303030 1px solid; } - -#g-add-photos-canvas { background-color: #101010; border: #303030 1px solid; } -#g-add-photos-button { border: #303030 1px solid; color: #bbb; } -#g-add-photos-status { background-color: #101010; border: #303030 1px solid; } - -#g-add-photos-status li.g-success { background: #d9efc2 url('images/ico-success.png') no-repeat .4em 50%; } -#g-add-photos-status li.g-error { background: #f6cbca url('images/ico-error.png') no-repeat .4em 50%; color: #f00; } - -/* forms.css - Organize ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content.html_ajax #g-organize { border: #303030 1px solid; } - -#g-organize-detail { border-left: #303030 1px solid; } -#g-organize .g-message-block { border-bottom: #303030 1px solid; } -.g-organize-microthumb-grid-cell { background-color: #303030; } -.g-organize-microthumb { background-color: #707070; } -#g-organize-controls { border-top: #303030 1px solid; } - -/* forms.css - User Profile ~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-user-profile .g-avatar { border: 1px solid #888; background: #555; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* menus.css ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-site-menu ul { border: #000000 0 solid; } -#g-site-menu li a:hover { color: #000000; background-color: #303030; } -#g-site-menu li:hover, -#g-site-menu li.iemhover { border: #303030 1px solid; background-color: #303030; border-bottom: #000000 1px solid; } -#g-site-menu li ul { border: #000000 1px solid; } -#g-site-menu li ul li { border: #C0C0C0 0px solid; background-color: #212121; } -#g-site-menu li ul li:hover, -#g-site-menu li ul li.iemhover { border: #C0C0C0 0 solid; background-color: #303030; } - -.g-item .g-context-menu { background-image: url(images/ui-icons.png); } -.g-item .g-context-menu:hover { background: #181818 none; border: 1px #888 solid; } -.g-item .g-context-menu li li a:hover { background-color: #303030; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* modules.css - Exif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-exif-data table { border: #303030 1px solid; } -#sb-content #g-exif-data .g-even { background-color: #404040; } -#sb-content #g-exif-data .g-odd { background-color: #303030; } - -/* modules.css - Info module ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-metadata .g-description { border-top: 1px solid #737373; } - -/* modules.css - Image block ~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-image-block img { border: 1px solid #888; background: #555; } - -/* modules.css - Comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-comments .g-author { border-bottom: 1px solid #202628; color: #999; } -#g-comments-link { background-image: url(images/view-comments.png); } -#g-comment-detail>ul>li { border: 1px dotted #737373; } -#g-comment-form { border: 1px dotted #737373; } - -/* modules.css - Calendar ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-view-menu #g-calendarview-link { background-image: url(images/view-calendar.png); } -#g-view-calendar-form ul { border: 1px #888 solid; } -table.calendar { border: #a2adbc 1px solid; color: #616b76; } -table.calendar th { border-bottom: #a2adbc 1px solid; border-right: #a2adbc 1px solid; background: #d9e2e1; color: #616b76; } -table.calendar td { border-bottom: #a2adbc 1px solid; border-right: #a2adbc 1px solid; } -table.calendar td.title { background-color: #a2adbc; color: #fff; } -table.calendar td.title a { color: #fff !important; } -table.calendar td a { color: red !important; } - -/* modules.css - Search ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-quick-search-form input[type="text"] { background-color: transparent; border: 1px solid #737373; color: #BBB; } -#g-quick-search-form input[type="submit"] { background: transparent url(images/search.png) no-repeat center top; border: none; } - -/* modules.css - Basket ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#checkout legend { background: url(images/section.png) repeat-x; } \ No newline at end of file diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/ajax-loading.gif b/3.1/themes/greydragon/css/colorpacks/carbon/images/ajax-loading.gif deleted file mode 100644 index 0996045a..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/ajax-loading.gif and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/ico-album.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/ico-album.png deleted file mode 100644 index ac87ec4f..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/ico-album.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/ico-error.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/ico-error.png deleted file mode 100644 index c37bd062..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/ico-error.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/ico-separator.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/ico-separator.png deleted file mode 100644 index 3e158515..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/ico-separator.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/ico-success.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/ico-success.png deleted file mode 100644 index a9925a06..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/ico-success.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/search.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/search.png deleted file mode 100644 index 2d115cc8..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/search.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/section.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/section.png deleted file mode 100644 index 8180ecb3..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/section.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/ui-icons.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/ui-icons.png deleted file mode 100644 index 7d1723bf..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/ui-icons.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-calendar.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/view-calendar.png deleted file mode 100644 index 5442fa51..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-calendar.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-comments.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/view-comments.png deleted file mode 100644 index 5449126b..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-comments.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-full.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/view-full.png deleted file mode 100644 index 7145fd9d..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-full.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-fullsize.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/view-fullsize.png deleted file mode 100644 index ebd04237..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-fullsize.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-info.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/view-info.png deleted file mode 100644 index ff30501c..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-info.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-left.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/view-left.png deleted file mode 100644 index c59af5d0..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-left.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-right.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/view-right.png deleted file mode 100644 index 59505456..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-right.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-slideshow.png b/3.1/themes/greydragon/css/colorpacks/carbon/images/view-slideshow.png deleted file mode 100644 index 2fb53ad0..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/carbon/images/view-slideshow.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/colors.css b/3.1/themes/greydragon/css/colorpacks/greydragon/colors.css deleted file mode 100644 index 22a6d40e..00000000 --- a/3.1/themes/greydragon/css/colorpacks/greydragon/colors.css +++ /dev/null @@ -1,178 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * ColorPack: GreyDragon - Default color pack - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* styles.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -html { background-color: #1A2022; } -body { color: #BBB; background: url(images/background.gif) #1A2022 repeat-x; } - -h1 { border-bottom: #737373 1px solid; } -a { color: #6392CF !important; } -.ui-icon { background-image: url(images/ui-icons.png); } - -/* styles.css - Header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-header .g-message-block { border: 1px #888 solid; background-color: #AAA; color: #000; } -.g-breadcrumbs li { background: transparent url(images/ico-separator.png) no-repeat 0 0.2em; } - -/* styles.css - Footer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-footer { background: url(images/footer.png) #1A2022 repeat-x top !important; } - -/* styles.css - Album Layout ~~~~~~~~~~~~~~~~~~~~~~~~~*/ -#g-info .g-description { border: #737373 1px solid; } - -.g-thumbslide, .g-thumbslide-ext { border: 1px solid #303E43; background: #1E1E1E url('images/image-thumb.gif') repeat-x; } -.g-thumbcrop { border: 1px solid #303E43; } - -.g-album .g-thumbslide, -.g-album .g-thumbslide-ext { border-top: 1px solid #43565B; border-left: 1px solid #43565B; border-right: 4px double #43565B; border-bottom: 4px double #43565B; } -.g-photo .g-thumbslide, /* Need to compensate for double border in album's thumbs */ -.g-photo .g-thumbslide-ext { margin-bottom: 3px; } - -.g-thumbslide:hover .g-description { color: #fff; border-bottom: 1px solid #999; background: #1E1E1E; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } -.g-album .g-thumbslide:hover .g-description, -.g-album .g-thumbslide-ext .g-description { background: #1E1E1E url(images/ico-album.png) no-repeat 4px 2px; } - -.g-thumbslide:hover .g-metadata, -.g-thumbslide-ext:hover .g-metadata { border-top: 1px solid #999; background: #1E1E1E; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } - -/* styles.css - Photo Layout ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -div.g-resize { border: 1px solid #888; background: #555; } - -div.g-resize:hover .g-description { color: #fff; background: #1E1E1E; border-bottom: 1px solid #999; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } -div.g-resize .g-more { border: 1px solid #999; background: #1E1E1E; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } - -.g-movie { border: 1px solid #888; padding: 5px; background: #555; } - -/* styles.css - Reauthentificate ~~~~~~~~~~~~~~~~~~~~~*/ - -#g-reauthenticate-form ul { border: 1px #888 solid; } - -/* styles.css - Sidebar Blocks ~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-toolbar { border-bottom: 1px solid #737373; } - -/* styles.css - Sidebar Blocks : Common ~~~~~~~~~~~~~~*/ - -.g-block { border: 1px solid #737373; background-color: #101415; } -.g-block h2 { background: url(images/section.png) repeat-x; } - -/* styles.css - Sidebar Blocks : Buttons ~~~~~~~~~~~~~*/ - -#g-viewformat .g-viewthumb-left { background: url('images/view-left.png') no-repeat left top; } -#g-viewformat .g-viewthumb-right { background: url('images/view-right.png') no-repeat left top; } -#g-viewformat .g-viewthumb-full { background: url('images/view-full.png') no-repeat left top; } - -#g-slideshow-link { background: url("images/view-slideshow.png") top left no-repeat; } -.g-fullsize-link { background: url("images/view-fullsize.png") top left no-repeat; } -#g-exifdata-link { background: url("images/view-info.png") top left no-repeat; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* forms.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-body { background: #101415 url('images/ajax-loading.gif') no-repeat center center; } -#sb-title { border-left: #303030 1px solid; border-right: #303030 1px solid; background: #101415 url('images/section.png') repeat-x; } - -#sb-content.html_ajax p.g-error { color: red; } -#sb-content.html_ajax form { background-color: #101415; } -#sb-content.html_ajax>div { background-color: #101415; } - -/* styles.css - Photo Slideshow ~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-counter a { color: #fff !important; font-weight: bold; font-size: 11px; } - -/* forms.css - Permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-permissions .g-breadcrumbs { border: #303030 1px solid; } -#sb-content #g-edit-permissions-form { border: #303030 1px solid; } -#sb-content #g-move>ul { border: #303030 1px solid; } - -/* forms.css - Add item ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-add-photos-form .g-breadcrumbs { border: #303030 1px solid; } - -#g-add-photos-canvas { background-color: #101010; border: #303030 1px solid; } -#ag-add-photos-button { border: #303030 1px solid; color: #bbb; } -#g-add-photos-status { background-color: #101010; border: #303030 1px solid; } - -#g-add-photos-status li.g-success { background: url('images/ico-success.png') transparent no-repeat .4em 50%; } -#g-add-photos-status li.g-error { background: url('images/ico-error.png') transparent no-repeat .4em 50%; color: #f00; } - -/* forms.css - Organize ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content.html_ajax #g-organize { border: #303030 1px solid; } - -#g-organize-detail { border-left: #303030 1px solid; } -#g-organize .g-message-block { border-bottom: #303030 1px solid; } -.g-organize-microthumb-grid-cell { background-color: #303030; } -.g-organize-microthumb { background-color: #707070; } -#g-organize-controls { border-top: #303030 1px solid; } - -/* forms.css - User Profile ~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-user-profile .g-avatar { border: 1px solid #888; background: #555; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* menus.css ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-site-menu ul { border: #000000 0 solid; } -#g-site-menu li a:hover { color: #000000; background-color: #303030; } -#g-site-menu li:hover, -#g-site-menu li.iemhover { border: #303030 1px solid; background-color: #303030; border-bottom: #000000 1px solid; } -#g-site-menu li ul { border: #000000 1px solid; } -#g-site-menu li ul li { border: #C0C0C0 0px solid; background-color: #212121; } -#g-site-menu li ul li:hover, -#g-site-menu li ul li.iemhover { border: #C0C0C0 0 solid; background-color: #303030; } - -.g-item .g-context-menu { background-image: url(images/ui-icons.png); } -.g-item .g-context-menu:hover { background: #181818 none; border: 1px #888 solid; } -.g-item .g-context-menu li li a:hover { background-color: #303030; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* modules.css - Exif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-exif-data table { border: #303030 1px solid; } -#sb-content #g-exif-data .g-even { background-color: #404040; } -#sb-content #g-exif-data .g-odd { background-color: #303030; } - -/* modules.css - Info module ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-metadata .g-description { border-top: 1px solid #737373; } - -/* modules.css - Image block ~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-image-block img { border: 1px solid #888; background: #555; } - -/* modules.css - Comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-comments .g-author { border-bottom: 1px solid #202628; color: #999; } -#g-comments-link { background-image: url(images/view-comments.png); } -#g-comment-detail>ul>li { border: 1px dotted #737373; } -#g-comment-form { border: 1px dotted #737373; } - -/* modules.css - Calendar ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-view-menu #g-calendarview-link { background-image: url(images/view-calendar.png); } -#g-view-calendar-form ul { border: 1px #888 solid; } -table.calendar { border: #a2adbc 1px solid; color: #616b76; } -table.calendar th { border-bottom: #a2adbc 1px solid; border-right: #a2adbc 1px solid; background: #d9e2e1; color: #616b76; } -table.calendar td { border-bottom: #a2adbc 1px solid; border-right: #a2adbc 1px solid; } -table.calendar td.title { background-color: #a2adbc; color: #fff; } -table.calendar td.title a { color: #fff !important; } -table.calendar td a { color: red !important; } - -/* modules.css - Search ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-quick-search-form input[type="text"] { background-color: transparent; border: 1px solid #737373; color: #BBB; } -#g-quick-search-form input[type="submit"] { background: transparent url(images/search.png) no-repeat center top; border: none; } - -/* modules.css - Basket ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#checkout legend { background: url(images/section.png) repeat-x; } diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/ajax-loading.gif b/3.1/themes/greydragon/css/colorpacks/greydragon/images/ajax-loading.gif deleted file mode 100644 index 0996045a..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/ajax-loading.gif and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/background.gif b/3.1/themes/greydragon/css/colorpacks/greydragon/images/background.gif deleted file mode 100644 index b8083564..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/background.gif and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/footer.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/footer.png deleted file mode 100644 index 04d5ee54..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/footer.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/ico-album.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/ico-album.png deleted file mode 100644 index ac87ec4f..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/ico-album.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/ico-error.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/ico-error.png deleted file mode 100644 index c37bd062..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/ico-error.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/ico-separator.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/ico-separator.png deleted file mode 100644 index 3e158515..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/ico-separator.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/ico-success.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/ico-success.png deleted file mode 100644 index a9925a06..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/ico-success.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/image-thumb.gif b/3.1/themes/greydragon/css/colorpacks/greydragon/images/image-thumb.gif deleted file mode 100644 index bc3a192f..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/image-thumb.gif and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/search.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/search.png deleted file mode 100644 index 1bfa4115..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/search.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/section.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/section.png deleted file mode 100644 index 8180ecb3..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/section.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/ui-icons.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/ui-icons.png deleted file mode 100644 index 7ab15cae..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/ui-icons.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-calendar.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-calendar.png deleted file mode 100644 index 206ccd66..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-calendar.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-comments.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-comments.png deleted file mode 100644 index 293c587e..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-comments.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-full.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-full.png deleted file mode 100644 index b75de946..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-full.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-fullsize.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-fullsize.png deleted file mode 100644 index ed76257a..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-fullsize.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-info.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-info.png deleted file mode 100644 index 521439ce..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-info.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-left.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-left.png deleted file mode 100644 index b5b93c7a..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-left.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-right.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-right.png deleted file mode 100644 index a400c638..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-right.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-slideshow.png b/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-slideshow.png deleted file mode 100644 index c6a471ac..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/greydragon/images/view-slideshow.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/colors.css b/3.1/themes/greydragon/css/colorpacks/wind/colors.css deleted file mode 100644 index 09ab5a6a..00000000 --- a/3.1/themes/greydragon/css/colorpacks/wind/colors.css +++ /dev/null @@ -1,184 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * ColorPack: Wind - Wind theme-like color pack - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* styles.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -html { background-color: #ccc; } -body { color: #000; background-color: #ccc; padding-left: 10px; padding-right: 10px; } - -a { color: #33629f !important } -.ui-icon { background-image: url(images/ui-icons.png); } - -/* styles.css - Header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-header { background-color: #e8e8e8; border-bottom: #ccc 1px solid; } -#g-header .g-message-block { border: 1px #888 solid; background-color: #aaa; color: #000; } -.g-breadcrumbs li { background: transparent url(images/ico-separator.png) no-repeat 0 0.2em; } - -/* styles.css - Main ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-main { background-color: #fff; } - -/* styles.css - Footer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-footer { background-color: #e8e8e8; border-top: #ccc 1px solid; } - -/* styles.css - Album Layout ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-info h1, #g-album-header h1 { border-bottom: #ccc 1px solid; } -#g-info .g-description { border: #888 1px solid; } - -.g-thumbslide { border: 1px solid #707E83; background-color: #e8e8e8; } -.g-thumbcrop { border: 1px solid #707E83; } - -.g-album .g-thumbslide, -.g-album .g-thumbslide-ext { border-top: 1px solid #707E83; border-left: 1px solid #707E83; border-right: 4px double #707E83; border-bottom: 4px double #707E83; } -.g-photo .g-thumbslide, /* Need to compensate for double border in album's thumbs */ -.g-photo .g-thumbslide-ext { margin-bottom: 3px; } - -.g-thumbslide:hover .g-description { color: #000; border-bottom: 1px solid #999; background: #e8e8e8; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } -.g-album .g-thumbslide:hover .g-description, -.g-album .g-thumbslide-ext .g-description { background: #fff url(images/ico-album.png) no-repeat 4px 2px; } - -.g-thumbslide:hover .g-metadata, -.g-thumbslide-ext:hover .g-metadata { border-top: 1px solid #999; background: #e8e8e8; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } - -/* styles.css - Photo Layout ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -div.g-resize { border: 1px solid #888; background: #e8e8e8; } - -div.g-resize:hover .g-description { color: #000; background: #e8e8e8; border-bottom: 1px solid #999; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } -div.g-resize .g-more { border: 1px solid #999; background: #e8e8e8; filter:alpha(opacity=85); opacity:.85; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; } - -.g-movie { border: 1px solid #888; padding: 5px; background: #e8e8e8; } - -/* styles.css - Reauthentificate ~~~~~~~~~~~~~~~~~~~~~*/ - -#g-reauthenticate-form ul { border: 1px #888 solid; } - -/* styles.css - Sidebar Blocks ~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-toolbar { border-bottom: 1px solid #ccc; } - -/* styles.css - Sidebar Blocks : Common ~~~~~~~~~~~~~~*/ - -.g-block { border: 1px solid #ccc; } -.g-block h2 { background-color: #e8e8e8; } - -/* styles.css - Sidebar Blocks : Buttons ~~~~~~~~~~~~~*/ - -#g-viewformat .g-viewthumb-left { background: url('images/view-left.png') no-repeat left top; } -#g-viewformat .g-viewthumb-right { background: url('images/view-right.png') no-repeat left top; } -#g-viewformat .g-viewthumb-full { background: url('images/view-full.png') no-repeat left top; } - -#g-slideshow-link { background: url("images/view-slideshow.png") top left no-repeat; } -.g-fullsize-link { background: url("images/view-fullsize.png") top left no-repeat; } -#g-exifdata-link { background: url("images/view-info.png") top left no-repeat; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* forms.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-body { background: #fff url('images/ajax-loading.gif') no-repeat center center; } -#sb-title { border-left: #303030 1px solid; border-right: #303030 1px solid; background: #e8e8e8; color: #000; } -#sb-title-inner { color: #000; } - -#sb-content.html_ajax p.g-error { color: red; } -#sb-content.html_ajax form { background-color: #fff; } -#sb-content.html_ajax>div { background-color: #fff; } - -/* forms.css - Permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-permissions .g-breadcrumbs { border: #303030 1px solid; } -#sb-content #g-edit-permissions-form { border: #303030 1px solid; } -#sb-content #g-move>ul { border: #303030 1px solid; } - -/* forms.css - Add item ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-add-photos-form .g-breadcrumbs { border: #303030 1px solid; } - -#g-add-photos-canvas { background-color: #fff; border: #303030 1px solid; } -#g-add-photos-button { border: #303030 1px solid; } -#g-add-photos-status { background-color: #fff; border: #303030 1px solid; } - -#g-add-photos-status li.g-success { background: #d9efc2 url('images/ico-success.png') no-repeat .4em 50%; } -#g-add-photos-status li.g-error { background: #f6cbca url('images/ico-error.png') no-repeat .4em 50%; color: #f00; } - -/* forms.css - Organize ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content.html_ajax #g-organize { border: #303030 1px solid; } - -#g-organize-detail { border-left: #303030 1px solid; } -#g-organize .g-message-block { border-bottom: #303030 1px solid; } -.g-organize-microthumb-grid-cell { background-color: #fff; } -.g-organize-microthumb { background-color: #fff; } -#g-organize-controls { border-top: #303030 1px solid; } - -/* forms.css - User Profile ~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-user-profile h1 { border-bottom: #ccc 1px solid; } -#g-user-profile .g-avatar { border: 1px solid #888; background: #fff; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* menus.css ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-site-menu ul { border: #000000 0 solid; } -#g-site-menu li { background-color: #bdd2ff; } -#g-site-menu li a:hover { color: #000000; background-color: #cfdeff; } -#g-site-menu li:hover, -#g-site-menu li.iemhover { border: #303030 1px solid; background-color: #cfdeff; border-bottom: #cfdeff 1px solid; } -#g-site-menu li ul { border: #cfdeff 1px solid; } -#g-site-menu li ul li { border: #C0C0C0 0px solid; background-color: #bdd2ff; } -#g-site-menu li ul li:hover, -#g-site-menu li ul li.iemhover { border: #C0C0C0 0 solid; background-color: #ddf2ff; } - -.g-item .g-context-menu { background-image: url(images/ui-icons.png); } -.g-item .g-context-menu:hover { background: #bdd2ff none; border: 1px #888 solid; } -.g-item .g-context-menu li li a:hover { background-color: #ddf2ff; } - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* modules.css - Exif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-exif-data table { border: #303030 1px solid; } -#sb-content #g-exif-data .g-even { background-color: #A0A0A0; } -#sb-content #g-exif-data .g-odd { background-color: #C0C0C0; } - -/* modules.css - Info module ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-metadata .g-description { border-top: 1px solid #ccc; } - -/* modules.css - Image block ~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-image-block img { border: 1px solid #888; background: #555; } - -/* modules.css - Comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-comments .g-author { border-bottom: 1px solid #202628; color: #999; } -#g-comments-link { background-image: url(images/view-comments.png); } -#g-comment-detail>ul>li { border: 1px dotted #ccc; } -#g-comment-form { border: 1px dotted #ccc; } - -/* modules.css - Calendar ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-view-menu #g-calendarview-link { background-image: url(images/view-calendar.png); } -#g-view-calendar-form ul { border: 1px #888 solid; } -table.calendar { border: #a2adbc 1px solid; color: #616b76; } -table.calendar th { border-bottom: #a2adbc 1px solid; border-right: #a2adbc 1px solid; background: #d9e2e1; color: #616b76; } -table.calendar td { border-bottom: #a2adbc 1px solid; border-right: #a2adbc 1px solid; } -table.calendar td.title { background-color: #a2adbc; color: #fff; } -table.calendar td.title a { color: #fff !important; } -table.calendar td a { color: red !important; } - -/* modules.css - Search ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-quick-search-form input[type="text"] { background-color: transparent; border: 1px solid #ccc; color: #666; } -#g-quick-search-form input[type="submit"] { border: #c5dbec 1px solid; text-indent: 0; width: auto; height: auto; font: 80% arial, helvetica, clean, sans-serif; font-weight: bold; padding-top: 3px; padding-bottom: 3px; } -#g-search-results h1 { border-bottom: #ccc 1px solid; } - -/* modules.css - Basket ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#checkout legend { background-color: #e8e8e8; } \ No newline at end of file diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/ajax-loading.gif b/3.1/themes/greydragon/css/colorpacks/wind/images/ajax-loading.gif deleted file mode 100644 index 53dd589f..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/ajax-loading.gif and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/ico-album.png b/3.1/themes/greydragon/css/colorpacks/wind/images/ico-album.png deleted file mode 100644 index ac87ec4f..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/ico-album.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/ico-error.png b/3.1/themes/greydragon/css/colorpacks/wind/images/ico-error.png deleted file mode 100644 index c37bd062..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/ico-error.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/ico-separator.png b/3.1/themes/greydragon/css/colorpacks/wind/images/ico-separator.png deleted file mode 100644 index 3e158515..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/ico-separator.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/ico-success.png b/3.1/themes/greydragon/css/colorpacks/wind/images/ico-success.png deleted file mode 100644 index a9925a06..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/ico-success.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/ui-icons.png b/3.1/themes/greydragon/css/colorpacks/wind/images/ui-icons.png deleted file mode 100644 index a8bd54b5..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/ui-icons.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/view-calendar.png b/3.1/themes/greydragon/css/colorpacks/wind/images/view-calendar.png deleted file mode 100644 index 13e0e8fa..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/view-calendar.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/view-comments.png b/3.1/themes/greydragon/css/colorpacks/wind/images/view-comments.png deleted file mode 100644 index f33bdf19..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/view-comments.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/view-full.png b/3.1/themes/greydragon/css/colorpacks/wind/images/view-full.png deleted file mode 100644 index e465d366..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/view-full.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/view-fullsize.png b/3.1/themes/greydragon/css/colorpacks/wind/images/view-fullsize.png deleted file mode 100644 index 58b3e0b4..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/view-fullsize.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/view-info.png b/3.1/themes/greydragon/css/colorpacks/wind/images/view-info.png deleted file mode 100644 index 2cc7a68e..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/view-info.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/view-left.png b/3.1/themes/greydragon/css/colorpacks/wind/images/view-left.png deleted file mode 100644 index b51e3368..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/view-left.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/view-right.png b/3.1/themes/greydragon/css/colorpacks/wind/images/view-right.png deleted file mode 100644 index bd72adfc..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/view-right.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/colorpacks/wind/images/view-slideshow.png b/3.1/themes/greydragon/css/colorpacks/wind/images/view-slideshow.png deleted file mode 100644 index 61bf18e1..00000000 Binary files a/3.1/themes/greydragon/css/colorpacks/wind/images/view-slideshow.png and /dev/null differ diff --git a/3.1/themes/greydragon/css/forms.css b/3.1/themes/greydragon/css/forms.css deleted file mode 100644 index ab246779..00000000 --- a/3.1/themes/greydragon/css/forms.css +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * CSS rules related to forms/dialogs - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* forms.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -input[type="submit"], .g-button, button { cursor: pointer; /* hand-shaped cursor */ cursor: hand; /* for IE 5.x */ font-size: 0.8em; color: #333 !important; padding: 2px 10px; margin-top: 0.4em; border: 1px solid; border-color: #999 #666 #666 #999; background-color: #ddd; font-weight: normal; } - -#sb-content.html_ajax { padding: 0 0.8em; margin: 0; } -#sb-content.html_ajax p.g-error { padding-top: 0.4em; } - -#sb-content.html_ajax form { background-color: #101415; overflow: hidden; } -#sb-content.html_ajax form fieldset { border: none; } -#sb-content.html_ajax form legend { display: none; width: 100%; } -#sb-content.html_ajax form ul { padding: 0; } -#sb-content.html_ajax form li { padding-top: 0.2em; } -#sb-content.html_ajax form>fieldset>ul { margin: 0 2px; } -#sb-content.html_ajax form label { display: block; padding: 0.2em 0; } -#sb-content.html_ajax form textarea { width: 99%; height: 4em; } -#sb-content.html_ajax input[type="submit"]{ margin: 6px 0; } -#sb-content.html_ajax input[type="text"], -#sb-content.html_ajax input[type="password"] { width: 99%; } -#sb-content.html_ajax>div { height: 94%; padding-top: 0.2em; overflow: auto; } -#sb-content #g-text { min-height: 6em; } - -#sb-content fieldset fieldset { border: none; } -#sb-content fieldset fieldset li { float: left; display: inline; margin-right: 1em; } - -/* forms.css - Login ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-login-form { width: 100%; } -#sb-content #g-login form ul { min-height: 10em; } -#sb-content #g-password-reset { margin-left: 0.4em; } - -/* forms.css - Edit Permissions ~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-permissions fieldset { border: none; margin: 1px; overflow: auto; width: 100%; } -#sb-content #g-permissions .g-breadcrumbs { position: static; padding: 0.4em; font-size: small; margin: 0.4em 0; } -#sb-content #g-permissions .g-breadcrumbs .g-first { padding-left: 0; } - -#sb-content #g-edit-permissions-form { margin: 0.4px 0; } -#sb-content #g-edit-permissions-form>fieldset>legend { display: none; } -#sb-content #g-edit-permissions-form>fieldset>table { font-size: small; } -#sb-content #g-edit-permissions-form>fieldset>table th, -#sb-content #g-edit-permissions-form>fieldset>table td { padding: 1px 2px; } - -/* forms.css - Delete Item ~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-confirm-delete { height: 5em; padding: 0.8em 0 0 0; } - -/* forms.css - Move Item ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-move>ul { height: 290px; margin-bottom: 0.4em; padding: 10px; overflow: auto; } -#sb-content #g-move>form { background: none; } - -/* forms.css - Add photo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-add-photos-form { height: 96%; } -#sb-content #g-add-photos-form .g-breadcrumbs { position: static; margin: 4px 0 0 0; padding: 4px; font-size: x-small; } -#sb-content #g-add-photos-form .g-breadcrumbs li { padding-top: 0; } -#sb-content #g-add-photos-form .g-breadcrumbs .g-first { padding-left: 0; } - -#g-add-photos-canvas { margin-top: 4px; height: 100px; } -#g-add-photos-button { padding: 2px 8px; z-index: 10; zoom: 1; } -#g-uploadifyUploader { z-index: 1005; zoom: 1; } -#g-uploadifyQueue { overflow: auto; height: 100%; } -#g-add-photos-status { margin-top: 4px; height: 90px; overflow: auto; } -#g-add-photos-status #g-action-status { margin: 0 0 1px 0; width: 100%; } -#g-add-photos-status #g-action-status li { margin: 0 0 1px 0; padding: 2px 0; text-indent: 30px; width: 100%; } - -/* forms.css - Organize ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content.html_ajax #g-organize { height: 440px; } -#g-organize #g-organize-content-pane { display: block; height: 440px; width: 690px; margin: 0 !important; overflow: hidden; } -#g-organize #g-organize-content-pane>div { float: left; height: 440px; } -#g-organize #g-organize-content-pane #g-organize-tree-container { overflow: auto; width: 164px; height: 428px; padding: 0 2px 0 4px !important; } -#g-organize #g-organize-detail { width: 518px; } -#g-organize #g-organize-detail .g-message-block li { padding: 0; } -#g-organize #g-organize-tree-container>ul { font-size: x-small; } -#g-organize #g-organize-tree-container>ul ul { padding: 0px; } -#g-organize #g-organize-album-tree { padding: 0; } -#g-organize .g-message-block { padding: 4px 0 4px 10px; } -#g-organize-microthumb-panel { background-color: transparent; border: none; height: 360px; } -#g-organize-microthumb-grid { position: static; height: 360px; border-style: none; padding: 0 2px !important; } -.g-organize-microthumb-grid-cell { float: left; margin: 2px; } -.g-organize-microthumb-grid-cell .ui-icon-note { background-position: -194px -144px; left: 8px; bottom: 4px; } -#g-organize-controls { position: absolute; background-color: transparent; padding: 6px 10px; } -#g-organize-controls li { display: inline; } -.g-organize-album-text { border: transparent 1px solid; } -#g-organize-close { display: none; } - -/* forms.css - User Profile ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-user-profile h1 { padding-bottom: 1px; margin: 0 0; } -#g-user-profile>div { margin: 2em 0 1em 10em; } -#g-user-profile .g-block-content { text-align: left; } -#g-user-profile .g-avatar { float: left; padding: 2px; } - -#g-user-profile th { text-align: left; padding-right: 20px; } -#g-change-email-user-form { min-height: 200px; } -#g-edit-user-form ul { min-height: 200px; } - -#g-quick-search-form input[type="submit"] { filter: none; margin-top: 0; } \ No newline at end of file diff --git a/3.1/themes/greydragon/css/layout.css b/3.1/themes/greydragon/css/layout.css deleted file mode 100644 index db55e4af..00000000 --- a/3.1/themes/greydragon/css/layout.css +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * CSS rules related to general layout - * Defined as 70em wide - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* layout.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -html { overflow: auto; overflow: -moz-scrollbars-vertical; overflow-y: scroll; } -* { margin: 0px; } -body { min-width: 70em; padding: 0; margin: 0; } - -.g-hideitem { display: none; } - -/* layout.css - Header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-header { position: relative; min-width: 70em; z-index: 5; } - -/* layout.css - Main ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-main { min-width: 69.7em; height: auto; bottom: auto; } -#g-main-in { min-width: 69.7em; height: 100%; overflow: auto; bottom: auto; } -#g-column-left { float: left; width: 16em; min-height: 32em; overflow: hidden; height: 100%; } -#g-column-right { float: right; width: 16em; min-height: 32em; overflow: hidden; height: 100%; } -#g-column-center { margin: 0 17em 0 17em; min-height: 32em; overflow: hidden; height: 100%; } -#g-column-centerleft { margin: 0; min-height: 32em; overflow: hidden; height: 100%; } -#g-column-centerright { margin: 0; min-height: 32em; overflow: hidden; height: 100%; } -#g-column-centerfull { position: relative; margin: 0 0; min-height: 31em; overflow: hidden; height: 100%; } - -/* layout.css - Footer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-footer { position: relative; height: auto; min-width: 70em; min-height: 4em; clear: both; display: block; overflow: auto; } -#g-footer-leftside { float: left; display: inline; } -#g-footer-rightside { float: right; display: inline; } - diff --git a/3.1/themes/greydragon/css/menus.css b/3.1/themes/greydragon/css/menus.css deleted file mode 100644 index 3ba173f2..00000000 --- a/3.1/themes/greydragon/css/menus.css +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * CSS rules related to menus - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* menus.css - Main menu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-site-menu { position: absolute; left: 24em; } -#g-site-menu.default { bottom: 0; } -#g-site-menu.top { top: 0; } -#g-site-menu ul { float: left; padding-left: 0; width: 100%; white-space: nowrap; z-index: 10; } -#g-site-menu ul ul ul { padding-top: 0; } -#g-site-menu a { display: block; padding: 0.2em 0.4em; text-align: center; width: auto; letter-spacing: 0; cursor: pointer; } -#g-site-menu li { float: left; padding: 0; background-color: transparent; border: transparent 1px solid; z-index: 10; } -#g-site-menu li a:hover { cursor: pointer; } -#g-site-menu li ul a { text-align: left; padding: 0.3em 0; text-indent: 0.8em; letter-spacing: 0; cursor: pointer; } -#g-site-menu li ul a:hover { background-image: none; cursor: pointer; } -#g-site-menu li ul { position: absolute; margin: 0 0 0 -1px; width: 14em; height: auto; left: -999em; } - -#g-site-menu li li { width: 14em; padding-right: 0; } -#g-site-menu li ul a { width: 14em; } -#g-site-menu li ul ul { margin: -1.9em 0 0 14em; } -#g-site-menu li:hover ul ul, -#g-site-menu li:hover ul ul ul, -#g-site-menu li.iemhover ul ul, -#g-site-menu li.iemhover ul ul ul { left: -999em; } -#g-site-menu li:hover ul, -#g-site-menu li li:hover ul, -#g-site-menu li li li:hover ul, -#g-site-menu li.iemhover ul, -#g-site-menu li li.iemhover ul, -#g-site-menu li li li.iemhover ul { left: auto; } - -#g-site-menu>ul>li>ul { display: none; } - -#g-site-menu .ui-icon-rotate-ccw, -#g-site-menu .ui-icon-rotate-cw { display: none; } - -/* menus.css - Context menu ~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-item .g-context-menu { position: absolute; margin: 0; padding: 0; top: 6px; left: 196px; width: 14px; height: 14px; background-position: -178px -144px; z-index: 3; } -.g-item .g-context-menu li { width: 100%; padding: 0; margin: 0; text-indent: -9999px; } -.g-item .g-context-menu>li>a { font-size: 0em; } -.g-item .g-context-menu:hover { top: 4px; left: 6px; width: 200px; height: auto; z-index: 100; } -.g-item .g-context-menu ul { padding: 0; margin: 0; } -.g-item .g-context-menu li li { display: none; } -.g-item .g-context-menu li li a { display: block; padding: 4px 6px; } -.g-item .g-context-menu:hover li li { display: block; text-indent: 0px; } -.g-item .g-context-menu li li a.ui-icon-rotate-ccw, -.g-item .g-context-menu li li a.ui-icon-rotate-cw { display: none; } - -.g-item.g-detail .g-context-menu { left: auto; right: 6px; } -.g-item.g-detail .g-context-menu:hover { left: auto; right: 6px; } \ No newline at end of file diff --git a/3.1/themes/greydragon/css/modules.css b/3.1/themes/greydragon/css/modules.css deleted file mode 100644 index 371434f8..00000000 --- a/3.1/themes/greydragon/css/modules.css +++ /dev/null @@ -1,135 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * CSS rules related to modules - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* modules.css - ShadowBox Skin ~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-title { overflow: hidden; } -#sb-title-inner { font-size: 10pt; font-weight: bold; padding-left: 10px; } -#sb-nav #sb-nav-close { background-image: url('../images/close.png'); width: 60px; } -#sb-container > #sb-overlay { min-height: 530px; overflow: auto; } - -/* modules.css - Exif Data ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#sb-content #g-exif-data { width: auto; background-image: none; } -#sb-content #g-exif-data table { width: 100%; } -#sb-content #g-exif-data td { padding: 0.4em; } - -/* modules.css - Image Block ~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-image-block>div { margin-left: 1px; margin-right: 1px; } -.g-image-block { text-align: center; } -.g-image-block img { padding: 5px; } - -/* modules.css - RSS Feeds ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -ul#g-feeds { padding: 0; margin: 0; } - -/* modules.css - Tags ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-tag-cloud ul { padding: 0; font-size: 100%; } -#g-tag-cloud ul li { line-height: 1.2em; } -#g-tag-cloud ul li span { display: none; } -#g-add-tag-form { display: none; } - -/* modules.css - Comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-comments { margin-top: 2em; padding-top: 0.4em; float: left; width: 100%; } -#g-comments ul li { margin: 0.4em 0; } -#g-comments .g-author { height: 32px; line-height: 32px; } -#g-comments .g-avatar { height: 32px; margin-right: .4em; width: 32px; } - -#g-admin-comment-button { width: 27px; right: 0.2em; text-indent: -900em; } -#g-comments-link { background-position: top left; background-repeat: no-repeat; } -#g-comments-link:hover { background-position: left bottom; } -#g-comment-detail ul { margin-top: 2em; padding: 0; } -#g-comment-detail>ul>li { margin: 4px 0; padding: 6px; min-height: 40px; } -#g-comment-detail div { margin-top: 6px; padding-bottom: 8px; } - -#g-comment-form fieldset { border: none; } -#g-comment-form legend { display: none; width: 100%; } -#g-comment-form ul { padding: 0; } -#g-comment-form>fieldset>ul { margin: 0px 10px; } -#g-comment-form label { display: block; } -#g-comment-form textarea { width: 99%; height: 140px; } -#g-comment-form input[type="text"], -#g-comment-form input[type="password"] { width: 99%; } - -/* modules.css - Gallery Stats ~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-gallerystats ul { padding: 0; font-size: x-small; } - -/* modules.css - Info ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-metadata ul { padding: 0; } -#g-metadata .g-description { margin-top: 0.4em; padding: 0.4em 0; } - -/* modules.css - Calendar ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-calendarview-link:hover { background-position: left bottom; } - -#g-view-calendar-form fieldset { border: none; } -#g-view-calendar-form ul { padding: 8px; } -#g-view-calendar-form li { padding-top: 8px; display: inline; padding-left: 10px; } -#g-view-calendar-form label { margin: 4px 0; } -#g-view-calendar-form select { margin: 4px 10px; } - -table.calendar { border-spacing: 1px; } -table.calendar td.title a { font-weight: bold; } - -/* modules.css - ClustrMaps ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-clustrmaps .g-block-content { text-align: center; } - -/* modules.css - GPS Info ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-exif-gps-maps ul { padding-left: 0; } - -/* modules.css - Search ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-quick-search-form { position: absolute; top: 3em; right: 1em; background: none transparent; } -#g-quick-search-form label { display: none; } -#g-quick-search-form li { display: inline; float: left; padding: 0px; } - -#g-quick-search-form input[type="text"] { width: 150px; } -#g-quick-search-form input[type="submit"] { display: block; width: 23px; height: 23px; text-indent: -9999px; overflow: hidden; } - -/* modules.css - Basket ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.basketbuttons span.ui-icon { display: none; } -#payment { height: 100%; margin-left: 10px; } -#payment p { padding: 4px; } -#basketForm { width: 100%; float:right; } -#checkout { } -#checkout fieldset { border: none; } -#checkout legend { width: 100%; padding: 4px 4px 4px 8px; font-size: 1em; font-weight: bold; } -#checkout ul { padding: 8px; } -#checkout li { padding-top: 8px; display: inline; } -#checkout label { margin: 4px 0; } -#checkout select { margin: 4px 10px; } - -#checkout textarea { display: block; clear: both; padding: .2em; width: 90%; } - -/* modules.css - Register ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-welcome-message p { padding-bottom: 6px; } -#g-change-password-user-form { height: 100%; } - -/* modules.css - Localization ~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#l10n-client .labels { border-top: white 1px solid; height: 1.7em; } -#l10n-client h2 { padding-top: 0.4em; padding-bottom: 0.3em; } -#l10n-client .label.translation { margin-top: -0.4em; height: 1.7em; } -#l10n-client #l10n-client-toggler { line-height: 1.7em; height: 1.7em; } -#l10n-client .string-list li { font-size: 0.8em; line-height: 1.1em; } -#l10n-client #l10n-client-string-select { width: 24%; } -#l10n-client #l10n-client-string-select .string-list { border: 1px #ccc solid; } -#l10n-client #g-l10n-search-form ul { padding: 0; } -#l10n-client #l10n-client-string-editor { margin-left: 1em; } -#l10n-client-string-editor .source .source-text { margin: 0 0.4em 0 0; border: 1px #ccc solid; padding: 0.4em; line-height: 1em; } -#l10n-client-string-editor .translation { height: 19em; } -#l10n-client #l10n-edit-translation { width: 97%; height: 17em; border: 1px #ccc solid; font-family: monospace; padding: 0.4em; } diff --git a/3.1/themes/greydragon/css/old_ie.css b/3.1/themes/greydragon/css/old_ie.css deleted file mode 100644 index 9a5da7b8..00000000 --- a/3.1/themes/greydragon/css/old_ie.css +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * CSS rules - IE 6 hacks - */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* old_ie.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -body { word-wrap: break-word; font-size: 100.1%; } - -.g-item .g-metadata:hover { padding: 0px 0 4px 6px; } -#g-quick-search-form input[type="submit"] { padding: 60px 0 0 0; } -#g-column-centerleft { margin: 0 19em 0 0; } -#g-column-centerright { margin: 0 0 0 19em; } diff --git a/3.1/themes/greydragon/css/screen.css b/3.1/themes/greydragon/css/screen.css deleted file mode 100644 index 17ecf082..00000000 --- a/3.1/themes/greydragon/css/screen.css +++ /dev/null @@ -1,224 +0,0 @@ -/** - * Gallery 3 Grey Dragon Theme - * Copyright (C) 2006-2010 Serguei Dosyukov - * - * CSS rules - Kitchen sync - * - * Color rules for font/background/lines can be found in dedicated colorpack files - */ - -@import url(layout.css); -@import url(menus.css); -@import url(forms.css); -@import url(modules.css); - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* screen.css - Common ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -body { font-family: Arial, verdana, sans-serif; font-size: 0.9em; } - -a { text-decoration: none; outline: none; -moz-outline-style: none; } -a:focus, a:active, a:hover { text-decoration: none; outline: none; } -img { border: none; } -p { text-indent: 0; } -ul { list-style: none none; } - -h1 { font-weight: bold; font-size: 1.1em; padding-bottom: 1px; } -h2 { font-weight: bold; font-size: 1.1em; } -h3 { font-weight: bold; } -h4 { font-weight: bold; } -h5 { font-weight: bold; } - -.txtright { text-align: right; } -.g-metadata { overflow: hidden; } -.g-avatar { float: right; } - -.ui-icon { display: inline-block; zoom: 1; width: 16px; height: 15px; } -.ui-icon-first { background-position: -162px -178px; } -.ui-icon-first-d { background-position: -162px -162px; } -.ui-icon-prev { background-position: -178px -178px; } -.ui-icon-prev-d { background-position: -178px -162px; } -.ui-icon-parent { background-position: -226px -178px; } -.ui-icon-parent-d { background-position: -226px -162px; } -.ui-icon-next { background-position: -194px -178px; } -.ui-icon-next-d { background-position: -194px -162px; } -.ui-icon-last { background-position: -210px -178px; } -.ui-icon-last-d { background-position: -210px -162px; } -.ui-icon-signal-diag { background-position: -16px -178px; } -.ui-icon-info { background-position: -16px -144px; } -.ui-icon-plus { background-position: -14px -129px; } -.ui-icon-minus { background-position: -46px -129px; } -.ui-icon-note { background-position: -66px -98px; } - -.ui-icon-comment { background-position: -227px -219px; width: 27px; height: 20px; } -.ui-icon-left .ui-icon { float: left; margin-right: .2em; } -.ui-icon-right .ui-icon { float: right; margin-left: .2em; } - -/* screen.css - Header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-header { height: 90px; padding: 0; font-size: 0.9em; } - -#g-logo { position: absolute; top: 8px; left: 16px; } - -.g-breadcrumbs { position: absolute; bottom: 4px; background-color: transparent; } -.g-breadcrumbs.default { right: 14px; } -.g-breadcrumbs.left { left: 304px; padding-left: 0; } -.g-breadcrumbs li { display: inline; padding-left: 1em; padding-right: 0.4em; } -.g-breadcrumbs li.g-first { background-image: none; } -.g-breadcrumbs li.g-active { padding-right: 0; } - -#g-header .g-message-block { position: absolute; z-index: 10; min-width: 30em; padding: 4px 6px; right: 20em; top: 34px; overflow: hidden; font: bold 9pt Arial, verdana, sans-serif; text-align: center; } - -#g-header #g-login-menu { position: absolute; top: 0.5em; right: 1em; background-color: transparent; display: none; } - -/* screen.css - Main ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-main { display: block; margin: 0; } -#g-main-in { display: block; position: relative; } - -#g-column-center, #g-column-centerleft { padding: 6px 6px 6px 16px; } -#g-column-centerfull { padding: 6px 12px 6px 10px; } -#g-column-centerright { padding: 6px 12px 6px 6px; } -#g-column-left { padding: 6px 4px 6px 10px; } -#g-column-right { padding: 6px 10px 6px 4px; } - -/* screen.css - Footer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-footer { padding: 6px 6px 6px 14px; zoom: 1; font-size: 0.9em; } -#g-footer ul { float: left; padding: 0; text-align: left; } -#g-footer li { padding: 0 0 2px 0; } - -#g-footer #g-login-menu { position: absolute; bottom: 0.5em; right: 1em; background-color: transparent; display: none; } - -#g-login-menu li { display: inline; padding-left: 1.2em; } -#g-logout-link { float: none; margin-right: 0; } - -#g-copyright { font-size: x-small; } -#g-footer #g-footer-rightside { float: right; padding-right: 6px; text-align: right; } -#g-credits { margin-right: 14px; } - -/* screen.css - Pagination ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-paginator { display: inline-block; width: 100%; padding: 4px 0 0 0; zoom: 1; } -.g-paginator li { display: inline; float: left; margin-left: 0; zoom: 1; } -.g-paginator a { padding: 0 0 0 2px; } - -.g-paginator .g-pagination { width: 80%; font-size: 0.8em; } -.g-paginator .g-navigation { text-align: right; width: 20%; } - -/* screen.css - Album grid ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-album-grid { padding: 6px 0 0 0; width: 100%; display: inline-block; } -#g-album-grid .g-item { position: relative; float: left; margin: 4px 0; min-width: 212px; width: 33%; zoom: 1; } /* amargin-right: 10px; */ -#g-album-grid .g-extra-column { width: 23%; } -#g-album-grid .g-item p { text-align: center; } -#g-album-grid h2 { position: absolute; top: 164px; left: 12px; width: 150px; font: 100%/100% Arial, Helvetica, sans-serif; } -#g-album-grid h2 a { display: block; margin-top: 4px; font: bold 0.8em Arial, Helvetica, Verdana, Sans-Serif; letter-spacing: 0.1em; text-transform: uppercase; min-height: 2em; } - -/* screen.css - Thumbs : Common ~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-thumbcrop { overflow: hidden; position: relative; width: 200px; min-height: 133px; } - -.g-thumbtype-flm .g-thumbcrop { height: 150px; } -.g-thumbtype-dgt .g-thumbcrop { height: 133px; } -.g-thumbtype-sqr .g-thumbcrop { height: 200px; } -.g-album .g-description strong { padding-left: 16px; } - -/* screen.css - Thumbs : Overlay ~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-thumbslide { font-size: 0.9em; width: 208px; min-height: 139px; padding-top: 6px; padding-left: 6px; } -.g-thumbslide.g-thumbtype-flm { height: 158px; } -.g-thumbslide.g-thumbtype-dgt { height: 141px; } -.g-thumbslide.g-thumbtype-sqr { height: 208px; } - -.g-thumbcrop a.g-thumlink { display: block; position: relative; } -.g-thumbslide .g-thumbcrop .g-description { display: none; } -.g-thumbslide:hover .g-description { display: block; position: absolute; top: 0; min-height: 32px; width: 100%; overflow: hidden; z-index: 3; font-weight: bold; font-size: 0.9em; letter-spacing: 0.1em; text-transform: uppercase; text-align: left; } -.g-thumbslide:hover .g-description strong { display: block; margin-left: 10px; padding-top: 2px; } -.g-album .g-thumbslide:hover .g-description strong { padding-left: 16px; } -.g-thumbslide .g-description strong { display: block; margin-left: 10px; padding-top: 2px; } - -.g-thumbslide .g-metadata { display: none; } -.g-thumbslide:hover .g-metadata { display: block; position: absolute; bottom: 7px; margin: 0 0 1px 1px; padding: 2px 4px 2px 6px; width: 190px; } -.g-thumbslide:hover .g-metadata li { padding: 0; margin: 0; font-size: 0.9em; } -.g-album .g-thumbslide:hover .g-metadata { bottom: 10px; } - -/* screen.css - Thumbs : Extended View mode ~~~~~~~~~~~~*/ - -.g-thumbslide-ext { font-size: 0.9em; width: 208px; min-height: 139px; padding-top: 6px; padding-left: 6px; } -.g-thumbslide-ext.g-thumbtype-flm { height: 188px; } -.g-thumbslide-ext.g-thumbtype-dgt { height: 171px; } -.g-thumbslide-ext.g-thumbtype-sqr { height: 238px; } - -.g-thumbslide-ext .g-description { display: block; margin-top: 2px; width: 200px; overflow: hidden; font-weight: bold; font-size: 0.9em; letter-spacing: 0.1em; text-transform: uppercase; text-align: left; } -.g-thumbslide-ext .g-description strong { display: block; } -.g-album .g-thumbslide-ext .g-description strong { padding-left: 24px; } - -.g-thumbslide-ext .g-metadata { display: none; } -.g-thumbslide-ext:hover .g-metadata { display: block; position: absolute; bottom: 37px; margin: 0 0 1px 1px; padding: 2px 4px 2px 6px; width: 190px; } -.g-thumbslide-ext:hover .g-metadata li { padding: 0; margin: 0; font-size: 0.9em; } -.g-album .g-thumbslide-ext:hover .g-metadata { bottom: 40px; } - -/* screen.css - Photo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-item { float: left; height: 100%; width: 100%; } -#g-photo { padding: 6px 0 6px 6px; text-align: center; float: left; height: 100%; width: 100%; } -div.g-resize { position: relative; left: 50%; float: left; padding: 5px; font-size: 0.9em; } -div.g-resize>a { float: left; overflow: hidden; } -div.g-resize>a img { float: left; } -div.g-resize .g-description { display: none; } -div.g-resize:hover .g-description { position: absolute; display: block; top: 0px; margin-top: 5px; text-align: left; padding: 10px; } -div.g-resize:hover .g-description strong { display: block; margin-bottom: 5px; text-transform: uppercase; } - -div.g-resize .g-more { display: block; position: absolute; right: 16px; top: 16px; padding: 4px 8px; } -div.g-resize:hover .g-more { display: none; visibility: hidden; } - -.ul-table { text-align: center; margin: 0px auto; padding: 0; list-style-type: none; clear: both; } -.ul-table li { float: left; text-align: center; } - -#g-info { display: inline-block; width: 100%; } -#g-info .g-description { margin-top: 4px; margin-bottom: 4px; padding: 4px; } -#g-movie { padding: 6px 0 6px 6px; position: relative; } - -.g-movie { margin: 0 auto; } - -#g-albumheader h1 { margin-bottom: 6px; } - -.g-description .g-metadata { padding: 0.4em 0 0 0; font-size: 0.8em; } -.g-description .g-metadata li { display: inline; padding-right: 1em; } - -/* screen.css - Sidebar ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -/* screen.css - Sidebar : Common ~~~~~~~~~~~~~~~~~~~~~~~*/ - -.g-block { margin-bottom: 4px; padding-bottom: 4px; position: relative; } -.g-block h2 { padding: 4px 4px 4px 8px; font-size: 1em; } -.g-block-content { margin: 4px 6px 0 6px; display: block; zoom: 1; } - -/* screen.css - Sidebar : Buttons ~~~~~~~~~~~~~~~~~~~~~~*/ - -#g-viewformat { z-index: 5; position: absolute; padding: 0; top: 6px; right: 10px; } -#g-viewformat li { float: left; margin-right: 2px; } -#g-viewformat span { line-height: 1px; text-indent: -900em; width: 17px; display: block; height: 15px; } -#g-viewformat span:hover, -#g-viewformat span.g-viewthumb-current { background-position: left bottom; } - -#g-view-menu { position: absolute; top: 6px; right: 70px; height: 16px; z-index: 5; zoom: 1; margin: 0 0 6px 0; padding: 0 0 4px 0; } -#g-view-menu.g-buttonset-shift { right: 6px; } -.g-toolbar { height: 1.1em; zoom: 1; margin: 0 0 4px 0; padding: 1px 0 3px 0; } -.g-menu { margin: 0; padding: 0; text-align: left; } -.g-menu li { display: inline; } - -.g-menu-element, -.g-menu-link { display: inline; float: left; margin-right: 4px; } - -.g-buttonset .g-menu-link { text-indent: -99999px; width: 22px; height: 15px; } - -#g-slideshow-link:hover, .g-fullsize-link:hover, #g-exifdata-link:hover { background-position: left bottom; } - -/* screen.css - Reauthentificate ~~~~~~~~~~~~~~~~~~~~~~ */ - -#g-reauthenticate-form fieldset { border: none; width: 260px; } -#g-reauthenticate-form ul { padding: 8px; } -#g-reauthenticate-form li { padding-top: 8px; } -#g-reauthenticate-form label { display: block; } -#g-reauthenticate-form input[type="password"] { width: 98%; } diff --git a/3.1/themes/greydragon/helpers/greydragon_theme.php b/3.1/themes/greydragon/helpers/greydragon_theme.php deleted file mode 100644 index 988da98c..00000000 --- a/3.1/themes/greydragon/helpers/greydragon_theme.php +++ /dev/null @@ -1,30 +0,0 @@ -' - . $theme_info->name . ' ' . $theme_info->version . ''; - } -} - diff --git a/3.1/themes/greydragon/images/avatar.jpg b/3.1/themes/greydragon/images/avatar.jpg deleted file mode 100644 index 71166cc4..00000000 Binary files a/3.1/themes/greydragon/images/avatar.jpg and /dev/null differ diff --git a/3.1/themes/greydragon/images/blue-grad.png b/3.1/themes/greydragon/images/blue-grad.png deleted file mode 100644 index 36e0f6bc..00000000 Binary files a/3.1/themes/greydragon/images/blue-grad.png and /dev/null differ diff --git a/3.1/themes/greydragon/images/button-grad-active-vs.png b/3.1/themes/greydragon/images/button-grad-active-vs.png deleted file mode 100644 index dc641725..00000000 Binary files a/3.1/themes/greydragon/images/button-grad-active-vs.png and /dev/null differ diff --git a/3.1/themes/greydragon/images/button-grad-vs.png b/3.1/themes/greydragon/images/button-grad-vs.png deleted file mode 100644 index 51c55a3d..00000000 Binary files a/3.1/themes/greydragon/images/button-grad-vs.png and /dev/null differ diff --git a/3.1/themes/greydragon/images/close.png b/3.1/themes/greydragon/images/close.png deleted file mode 100644 index d874f9aa..00000000 Binary files a/3.1/themes/greydragon/images/close.png and /dev/null differ diff --git a/3.1/themes/greydragon/images/donate.png b/3.1/themes/greydragon/images/donate.png deleted file mode 100644 index f36bb57a..00000000 Binary files a/3.1/themes/greydragon/images/donate.png and /dev/null differ diff --git a/3.1/themes/greydragon/images/favicon.ico b/3.1/themes/greydragon/images/favicon.ico deleted file mode 100644 index 66531d8e..00000000 Binary files a/3.1/themes/greydragon/images/favicon.ico and /dev/null differ diff --git a/3.1/themes/greydragon/images/missing-img.png b/3.1/themes/greydragon/images/missing-img.png deleted file mode 100644 index 12b7394f..00000000 Binary files a/3.1/themes/greydragon/images/missing-img.png and /dev/null differ diff --git a/3.1/themes/greydragon/js/ui.support.js b/3.1/themes/greydragon/js/ui.support.js deleted file mode 100644 index 353a30cc..00000000 --- a/3.1/themes/greydragon/js/ui.support.js +++ /dev/null @@ -1,156 +0,0 @@ -/* -* Grey Dragon Theme: JS support -*/ - -jQuery.fn.extend({ - myAjaxLoginSubmit: function() { - - var myAjaxLoginSubmitOps = { - dataType: 'json', - success: function(data) { - if (data.result == 'error') { - $('#g-login').html(data.form); - $().myAjaxLoginSubmit(); - } else { - Shadowbox.close(); - window.location.reload(); - } - } - }; - - $('form#g-login-form').one('submit', function() { - $(this).ajaxSubmit(myAjaxLoginSubmitOps); - return false; - }); - }, - - myAjaxSubmit: function() { - - var myAjaxSubmitOps = { - dataType: 'json', - success: function(data) { - if (data.result == 'error') { - $('#sb-content form').html(data.form); - $().myAjaxSubmit(); - } else { - Shadowbox.close(); - window.location.reload(); - } - } - }; - - $('form').one('submit', function() { - $(this).ajaxSubmit(myAjaxSubmitOps); - return false; - }); - }, - -/* - _ajaxify_dialog: function() { - var self = this; - $("#g-dialog form").ajaxForm({ - dataType: "json", - beforeSubmit: function(formData, form, options) { - form.find(":submit") - .addClass("ui-state-disabled") - .attr("disabled", "disabled"); - return true; - }, - success: function(data) { - if (data.form) { - var formData = unescape(data.form); - $("#g-dialog form").replaceWith(formData); - $("#g-dialog form :submit").removeClass("ui-state-disabled") - .attr("disabled", null); - self._ajaxify_dialog(); - self.form_loaded(null, $("#g-dialog form")); - if (typeof data.reset == 'function') { - eval(data.reset + '()'); - } - } - if (data.result == "success") { - if (data.location) { - window.location = data.location; - } else { - window.location.reload(); - } - } - } - }); -*/ - theme_ready: function() { - try { - Shadowbox.setup("a.g-fullsize-link", {player: 'img'}); - Shadowbox.setup("a.g-sb-preview", {player: 'img', gallery: "preview", animate: false, continuous: true, counterType: "skip", animSequence: "wh", slideshowDelay: 5 }); - - Shadowbox.setup(".g-dialog-link", {player: 'ajax', width: 500, height: 420, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup("a#g-login-link", {player: 'ajax', width: 340, height: 190, enableKeys: false, animate: false, onFinish: $().myAjaxLoginSubmit}); - Shadowbox.setup("a#g-exifdata-link", {player: 'ajax', width: 600, height: 420, animate: false}); - Shadowbox.setup("a#g-disclaimer", {player: 'ajax', width: 600, height: 420}); - - Shadowbox.setup("#g-site-menu .ui-icon-pencil", {player: 'ajax', width: 500, height: 420, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup(".g-context-menu .ui-icon-pencil", {player: 'ajax', width: 500, height: 420, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup("#g-site-menu .ui-icon-plus", {player: 'ajax', width: 500, height: 390, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup(".g-context-menu .ui-icon-plus", {player: 'ajax', width: 500, height: 390, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup("#g-site-menu .ui-icon-note", {player: 'ajax', width: 500, height: 370, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup(".g-context-menu .ui-icon-note", {player: 'ajax', width: 500, height: 370, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup("#g-site-menu .ui-icon-key", {player: 'ajax', width: 700, height: 300, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup(".g-context-menu .ui-icon-key", {player: 'ajax', width: 700, height: 300, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup("#g-site-menu #g-menu-organize-link", {player: 'ajax', width: 710, height: 460, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup(".g-context-menu #g-menu-organize-link",{player: 'ajax', width: 710, height: 460, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup(".g-context-menu .ui-icon-folder-open", {player: 'ajax', width: 400, height: 380, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup("#g-site-menu .g-quick-delete", {player: 'ajax', width: 400, height: 150, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - Shadowbox.setup(".g-context-menu .ui-icon-trash", {player: 'ajax', width: 400, height: 150, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup("#g-user-profile .g-dialog-link", {player: 'ajax', width: 500, height: 280, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - - Shadowbox.setup("#add_to_basket .g-dialog-link", {player: 'ajax', width: 500, height: 360, enableKeys: false, animate: false, onFinish: $().myAjaxSubmit}); - } catch (e) { } - - try { - $(".g-message-block").fadeOut(10000); - $(".g-context-menu .g-ajax-link").gallery_ajax(); - } catch (e) { } - - $("#g-site-menu>ul>li>ul").show(); - $("#g-login-menu").show(); - $(".g-context-menu").show(); - }, - -// gallery_dialog_postprocess: function(href, title) { -// Shadowbox.open({player: 'ajax', content: href, width: 500, height: 420, enableKeys: false, animate: false, title: title, onFinish: myAjaxSubmit}); -// } -}); - -/* -(function($) { - - $.widget("ui.gallery_dialog", { - _init: function() { - var self = this; - if (!self.options.immediate) { - this.element.click(function(event) { - event.preventDefault(); - var href = $(event.currentTarget).attr("href"); - var title = $(event.currentTarget).attr("title"); - setTimeout(function() { $().gallery_dialog_postprocess(href, title); }, 1000); - return false; - }); - } else { - var href = this.element.attr("href"); - var title = this.element.attr("title"); - setTimeout(function() { $().gallery_dialog_postprocess(href, title); }, 1000); - } - } - }); -})(jQuery); -*/ - -$(document).ready(function() { - $().theme_ready(); -}); diff --git a/3.1/themes/greydragon/libraries/MY_Theme_View.php b/3.1/themes/greydragon/libraries/MY_Theme_View.php deleted file mode 100644 index 4f579ec2..00000000 --- a/3.1/themes/greydragon/libraries/MY_Theme_View.php +++ /dev/null @@ -1,313 +0,0 @@ -ensurevalue(module::get_var("th_greydragon", $key), $default)); - } - - public function load_sessioninfo() { - $this->sidebarvisible = $_REQUEST['sb']; - - if (empty($this->sidebarvisible)): - $session = Session::instance(); - $_sidebar_mode = $session->get("gd_sidebar"); - if ($_sidebar_mode): - $this->sidebarvisible = $_sidebar_mode; - else: - $this->sidebarvisible = $this->ensureoptionsvalue("sidebar_visible", "right"); - endif; - else: - // Sidebar position is kept for 360 days - Session::instance()->set("gd_sidebar", $this->sidebarvisible, time() + 31536000); - endif; - - $this->sidebarallowed = $this->ensureoptionsvalue("sidebar_allowed", "any"); - $this->sidebarvisible = $this->ensurevalue($this->sidebarvisible, "right"); - - if ($this->sidebarallowed == "none") { $this->sidebarvisible = $this->ensureoptionsvalue("sidebar_visible", "right"); }; - if ($this->sidebarallowed == "right") { $this->sidebarvisible = "right"; } - if ($this->sidebarallowed == "left") { $this->sidebarvisible = "left"; } - - if ($this->item()): - if ($this->ensureoptionsvalue("sidebar_albumonly", FALSE)): - if (!$this->item()->is_album()): - $this->sidebarallowed = "none"; - $this->sidebarvisible = "none"; - endif; - endif; - endif; - - $this->logopath = $this->ensureoptionsvalue("logo_path", url::file("lib/images/logo.png")); - $this->show_guest_menu = $this->ensureoptionsvalue("show_guest_menu", FALSE); - $this->horizontal_crop = $this->ensureoptionsvalue("horizontal_crop", FALSE); - $this->thumb_descmode = $this->ensureoptionsvalue("thumb_descmode", "overlay"); - $this->photo_descmode = $this->ensureoptionsvalue("photo_descmode", "overlay"); - $this->is_thumbmeta_visible = ((!$this->ensureoptionsvalue("hide_thumbmeta", FALSE)) and module::is_active("info")); - $this->is_photometa_visible = ((!$this->ensureoptionsvalue("hide_photometa", TRUE)) and module::is_active("info")); - $this->disable_seosupport = $this->ensureoptionsvalue("disable_seosupport", FALSE); - $this->is_blockheader_visible = (!$this->ensureoptionsvalue("hide_blockheader", FALSE)); - $this->mainmenu_position = $this->ensureoptionsvalue("mainmenu_position", "default"); - $this->show_breadcrumbs = (!$this->ensureoptionsvalue("hide_breadcrumbs", FALSE)); - $this->loginmenu_position = ($this->ensureoptionsvalue("loginmenu_position", "default")); - $this->copyright = ($this->ensureoptionsvalue("copyright", null)); - $this->photonav_position = module::get_var("th_greydragon", "photonav_position", "top"); - $this->desc_allowbbcode = $this->ensureoptionsvalue("desc_allowbbcode", FALSE); - $this->enable_pagecache = $this->ensureoptionsvalue("enable_pagecache", FALSE); - $this->color_pack = $this->ensureoptionsvalue("color_pack", "greydragon"); - - $cssfile = gallery::find_file("css/colorpacks/" . $this->color_pack, "colors.css", false); - - if (!$cssfile): - $this->color_pack = 'greydragon'; - endif; - - switch (module::get_var("th_greydragon", "thumb_ratio")): - case "digital": - $this->crop_factor = 4/3; - $this->crop_class = 'g-thumbtype-dgt'; - break; - case "square": - $this->crop_factor = 1; - $this->crop_class = 'g-thumbtype-sqr'; - break; - case "film": - $this->crop_factor = 3/2; - $this->crop_class = 'g-thumbtype-flm'; - break; - case "photo": - default: - $this->crop_factor = 1; - $this->crop_class = 'g-thumbtype-sqr'; - break; - endswitch; - - $this->_thumb_size_y = floor($this->_thumb_size_x / $this->crop_factor); - } - - public function is_sidebarallowed($align) { - return (($this->sidebarallowed == "any") or ($this->sidebarallowed == $align)); - } - - public function breadcrumb_menu($theme, $parents) { - $content = ""; - - if ($theme->item() && !empty($parents)): - $content .= ''; - endif; - - return $content; - } - - protected function sidebar_menu_item($type, $url, $caption, $css) { - if (!$this->is_sidebarallowed($type)): - return ""; - endif; - - $iscurrent = ($this->sidebarvisible == $type); - $content_menu = '
  • '; - if (!$iscurrent): - $content_menu .= ''; - endif; - $content_menu .= '' . $caption . ''; - if (!$iscurrent): - $content_menu .= ''; - endif; - - return $content_menu . '
  • '; - } - - public function sidebar_menu($url) { - if ($this->sidebarallowed != "any"): - return ""; - endif; - - $content_menu = ($this->sidebar_menu_item("left", $url, "Sidebar Left", "left")); - $content_menu .= ($this->sidebar_menu_item("none", $url, "No Sidebar", "full")); - $content_menu .= ($this->sidebar_menu_item("right", $url, "Sidebar Right", "right")); - return '
      ' . $content_menu . '
    '; - } - - public function add_paginator($position) { - if (($this->photonav_position == "both") or ($this->photonav_position == $position)): - return ($this->paginator()); - else: - return ""; - endif; - } - - public function get_thumb_element($item, $addcontext) { - $item_class = $item->is_album() ? "g-album" : "g-photo"; - - if (($this->sidebarallowed == "none") and ($this->sidebarvisible == "none")): - $item_class .= " g-extra-column"; - endif; - - $content = '
  • '; - $content .= $this->thumb_top($item); - - if (($this->crop_factor == 1) and ($item->thumb_width > $item->thumb_height)): - $_shift = 'style="margin-top: ' . floor(($this->_thumb_size_y - $item->thumb_height) / 2) . 'px;"'; - else: - if (($this->crop_factor > 0) and ($item->thumb_width < $item->thumb_height)): - $_shift = 'style="margin-top: -' . floor(($item->thumb_height - $this->_thumb_size_y) / 2) . 'px;"'; - else: - $_shift = ""; - endif; - endif; - - $content .= '
    crop_class . '">

    '; - if ($this->thumb_descmode == "overlay"): - $content .= ''; - $content .= '' . $this->bb2html(html::purify($item->title), 2) . ''; // html::purify(text::limit_chars($item->title, 44, "…")) - $content .= ''; - endif; - $content .= ''; - if (($item->thumb_height == 0) or ($item->thumb_width == 0)): - $content .= 'No Image'; - else: - $content .= $item->thumb_img(); - endif; - $content .= '

    '; - - if ($this->thumb_descmode == "bottom"): - $content .= ''; - $content .= '' . $this->bb2html(html::purify($item->title), 2) . ''; - $content .= ''; - endif; - - if (($this->is_thumbmeta_visible) and (module::is_active("info"))): - $content .= ''; - endif; - - if ($addcontext): - $_text = $this->context_menu($item, "#g-item-id-{$item->id} .g-thumbnail"); - $content .= (stripos($_text, '
  • '))? $_text : null; - endif; - - $content .= '
  • '; - $content .= $this->thumb_bottom($item); - $content .= ''; - - return $content; - } - - // $mode: bit 1 - use mix mode ($mode in [1, 3]), bit 2 - strips bbcode ($mode in [2, 3]) - public function bb2html($text, $mode) { - // Syntax Sample: - // -------------- - // [img]http://elouai.com/images/star.gif[/img] - // [url="http://elouai.com"]eLouai[/url] - // [size="25"]HUGE[/size] - // [color="red"]RED[/color] - // [b]bold[/b] - // [i]italic[/i] - // [u]underline[/u] - // [list][*]item[*]item[*]item[/list] - // [code]value="123";[/code] - // [quote]John said yadda yadda yadda[/quote] - - static $bbcode_mappings = array( - "#\\[b\\](.*?)\\[/b\\]#" => "$1", - "#\\[i\\](.*?)\\[/i\\]#" => "$1", - "#\\[u\\](.*?)\\[/u\\]#" => "$1", - "#\\[s\\](.*?)\\[/s\\]#" => "$1", - "#\\[o\\](.*?)\\[/o\\]#" => "$1", - "#\\[url\\](.*?)\[/url\\]#" => "$1", - "#\\[url=(.*?)\\](.*?)\[/url\\]#" => "$2", - "#\\[mail=(.*?)\\](.*?)\[/mail\\]#" => "$2", - "#\\[img\\](.*?)\\[/img\\]#" => "\"\"", - "#\\[img=(.*?)\\](.*?)\[/img\\]#" => "\"$2\"", - "#\\[quote\\](.*?)\\[/quote\\]#" => "

    $1

    ", - "#\\[code\\](.*?)\\[/code\\]#" => "
    $1
    ", - "#\\[size=([^\\[]*)\\]([^\\[]*)\\[/size\\]#" => "$2", - "#\\[color=([^\\[]*)\\]([^\\[]*)\\[/color\\]#" => "$2", - "#\\[class=([^\\[]*)\\]([^\\[]*)\\[/class\\]#" => "$2", - "#\\[center\\](.*?)\\[/center\\]#" => "
    $1
    ", - "#\\[list\\](.*?)\\[/list\\]#" => "
      $1
    ", - "#\\[ul\\](.*?)\\[/ul\\]#" => "
      $1
    ", - "#\\[li\\](.*?)\\[/li\\]#" => "
  • $1
  • ", - ); - - static $bbcode_strip = '|[[\/\!]*?[^\[\]]*?]|si'; - - // Replace any html brackets with HTML Entities to prevent executing HTML or script - // Don't use strip_tags here because it breaks [url] search by replacing & with amp - if (($mode == 1) or ($mode == 3)): - $newtext = str_replace("<", "<", $text); - $newtext = str_replace(">", ">", $newtext); - $newtext = str_replace(""", "\"", $newtext); - else: - $newtext = str_replace("<", "<", $text); - $newtext = str_replace(">", ">", $newtext); - $newtext = str_replace("&quot;", """, $newtext); - endif; - - // Convert new line chars to html
    tags - $newtext = nl2br($newtext); - - if (strpos($text, "[") !== false): - if (($mode == 2) or ($mode == 3)): - $newtext = preg_replace($bbcode_strip, '', $newtext); - else: - $newtext = preg_replace(array_keys($bbcode_mappings), array_values($bbcode_mappings), $newtext); - endif; - endif; - - return stripslashes($newtext); //stops slashing, useful when pulling from db - } -} - -?> \ No newline at end of file diff --git a/3.1/themes/greydragon/theme.info b/3.1/themes/greydragon/theme.info deleted file mode 100644 index cea1d8d0..00000000 --- a/3.1/themes/greydragon/theme.info +++ /dev/null @@ -1,6 +0,0 @@ -name = "Grey Dragon Theme" -description = "A Crisp flexible theme with support of Color Packs and minimized on JS overhead" -version = 2.3.1 -author = "2010 Serguei Dosyukov" -site = 1 -admin = 0 diff --git a/3.1/themes/greydragon/thumbnail.png b/3.1/themes/greydragon/thumbnail.png deleted file mode 100644 index 4b80ecaf..00000000 Binary files a/3.1/themes/greydragon/thumbnail.png and /dev/null differ diff --git a/3.1/themes/greydragon/views/album.html.php b/3.1/themes/greydragon/views/album.html.php deleted file mode 100644 index 49fa5cf4..00000000 --- a/3.1/themes/greydragon/views/album.html.php +++ /dev/null @@ -1,55 +0,0 @@ - -
    - album_top() ?> -

    bb2html(html::purify($item->title), 1) ?>

    -
    - -add_paginator("top"); ?> - -photo_descmode == "top") and ($item->description)): ?> -
    bb2html(html::purify($item->description), 1) ?>
    - - -
      - - $child): ?> - get_thumb_element($child, TRUE) ?> - - - admin || access::can("add", $item)): ?> - id") ?> -
    • Add some.", - array("attrs" => html::mark_clean("href=\"$addurl\" class=\"g-dialog-link\""))) ?>
    • - -
    • - - -
    -album_bottom() ?> - -photo_descmode == "bottom") and ($item->description)): ?> -
    bb2html(html::purify($item->description), 1) ?>
    - - -add_paginator("bottom"); ?> diff --git a/3.1/themes/greydragon/views/block.html.php b/3.1/themes/greydragon/views/block.html.php deleted file mode 100644 index af29546f..00000000 --- a/3.1/themes/greydragon/views/block.html.php +++ /dev/null @@ -1,33 +0,0 @@ - - - - -
    - is_blockheader_visible): ?> -

    - -
    - -
    -
    diff --git a/3.1/themes/greydragon/views/dynamic.html.php b/3.1/themes/greydragon/views/dynamic.html.php deleted file mode 100644 index 1f787cf3..00000000 --- a/3.1/themes/greydragon/views/dynamic.html.php +++ /dev/null @@ -1,39 +0,0 @@ - -
    -
    - dynamic_top() ?> -
    -

    -
    - -add_paginator("top"); ?> - -
      - $child): ?> - get_thumb_element($child) ?> - -
    -dynamic_bottom() ?> - -add_paginator("bottom"); ?> diff --git a/3.1/themes/greydragon/views/exif_sidebar.html.php b/3.1/themes/greydragon/views/exif_sidebar.html.php deleted file mode 100644 index 115bfc86..00000000 --- a/3.1/themes/greydragon/views/exif_sidebar.html.php +++ /dev/null @@ -1 +0,0 @@ - diff --git a/3.1/themes/greydragon/views/info_block.html.php b/3.1/themes/greydragon/views/info_block.html.php deleted file mode 100644 index d3860584..00000000 --- a/3.1/themes/greydragon/views/info_block.html.php +++ /dev/null @@ -1,24 +0,0 @@ - -
      - owner): ?> -
    • - - owner->url): ?> - owner->display_name()) ?> - - owner->display_name()) ?> - -
    • - - captured): ?> -
    • - - captured)?> -
    • - - description): ?> -
    • - bb2html(html::purify($item->description), 1) ?> -
    • - -
    diff --git a/3.1/themes/greydragon/views/login_ajax.html.php b/3.1/themes/greydragon/views/login_ajax.html.php deleted file mode 100644 index 76028c4e..00000000 --- a/3.1/themes/greydragon/views/login_ajax.html.php +++ /dev/null @@ -1,41 +0,0 @@ - - - -
    - - - - -
    - diff --git a/3.1/themes/greydragon/views/movie.html.php b/3.1/themes/greydragon/views/movie.html.php deleted file mode 100644 index ec870608..00000000 --- a/3.1/themes/greydragon/views/movie.html.php +++ /dev/null @@ -1,43 +0,0 @@ - -
    - photo_top() ?> - -
    -

    bb2html(html::purify($item->title), 1) ?>

    -
    bb2html(html::purify($item->description), 1) ?>
    -
    - - add_paginator("top"); ?> - -
    - resize_top($item) ?> - movie_img(array("class" => "g-movie", "id" => "g-movie-id-{$item->id}")); ?> - context_menu($item, "#g-movie-id-{$item->id}") ?> - resize_bottom($item) ?> -
    - - add_paginator("bottom"); ?> - - photo_bottom() ?> -
    diff --git a/3.1/themes/greydragon/views/page.html.php b/3.1/themes/greydragon/views/page.html.php deleted file mode 100644 index 13664d65..00000000 --- a/3.1/themes/greydragon/views/page.html.php +++ /dev/null @@ -1,147 +0,0 @@ - - -load_sessioninfo(); ?> - - -enable_pagecache) and ($theme->item())): - // Page will expire in 60 seconds - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 60).'GMT'); - header("Cache-Control: public"); - header("Cache-Control: post-check=3600, pre-check=43200", false); - header("Content-Type: text/html; charset=UTF-8"); - header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); - endif; -?> - - -"; ?> - - - -item()): ?> -item()->is_album()): ?> - $theme->bb2html($theme->item()->title, 2))) ?> -item()->is_photo()): ?> - $theme->bb2html($theme->item()->title, 2))) ?> - - $theme->bb2html($theme->item()->title, 2))) ?> - -tag()): ?> - $theme->bb2html($theme->tag()->name, 2))) ?> - - - - -disable_seosupport): ?> - ' . "\n"; ?> - ' . "\n"; ?> - ' . "\n"; ?> - ' . "\n"; ?> - ' . "\n"; ?> - -" type="image/x-icon" /> -script("jquery.js") ?> -script("jquery.form.js") ?> -script("jquery-ui.js") ?> -page_subtype == "movie"): ?> -script("flowplayer.js") ?> - -script("gallery.ajax.js") ?> -head() ?> -" type="text/css" media="screen,print,projection" /> -color_pack . "/colors.css") ?>" type="text/css" media="screen,print,projection" /> - - - - - - - -page_top() ?> -
    - header_top() ?> - - - - - - -guest) or ($theme->show_guest_menu)): ?> -
    "> - site_menu() ?> -
    - - messages() ?> -header_bottom() ?> - -loginmenu_position == "header"): ?> - user_menu() ?> - - -show_breadcrumbs): ?> - breadcrumb_menu($theme, $parents); ?> - -
    -
    -
    - sidebar_menu($url) ?> -
    "> - - album_menu() ?> - - photo_menu() ?> - - movie_menu() ?> - - tag_menu() ?> - -
    - - sidebarvisible=="left"): ?> - ' ?> - sidebarvisible=="none"): ?> - - ' ?> - - - page_subtype != "login") and ($theme->page_subtype != "reauthenticate") and ($theme->sidebarvisible != "none")): ?> - - - sidebarvisible != "none")? "
    " : null ?> - - sidebarvisible == "left"): ?> - ' ?> - sidebarvisible == "none"): ?> - ' ?> - - ' ?> - - -
    - - - -page_bottom() ?> - - diff --git a/3.1/themes/greydragon/views/paginator.html.php b/3.1/themes/greydragon/views/paginator.html.php deleted file mode 100644 index 9b5e725e..00000000 --- a/3.1/themes/greydragon/views/paginator.html.php +++ /dev/null @@ -1,188 +0,0 @@ - - - -parent(); - endif; - $current_page = $page; - $total_pages = $max_pages; - // Prepare page url list - for ($i = 1; $i <= $total_pages; $i++): - $_pagelist[$i] = url::site(url::merge(array("page" => $i))); - endfor; - break; - case "item": - if ($item): - $parent = $item->parent(); - endif; - $current_page = $position; - $total_pages = $total; - $siblings = $item->parent()->children(); - for ($i = 1; $i <= $total; $i++): - $_pagelist[$i] = $siblings[$i-1]->url(); - endfor; - break; - default: - $current_page = 1; - $total_pages = 1; - $_pagelist[1] = url::site(); - break; - } - - if ($total_pages <= 1): - $pagination_msg = " "; - else: - $pagination_msg = t("Page:") . ' '; - if ($total_pages < 13): - for ($i = 1; $i <= $total_pages; $i++): - if ($i == $current_page): - $pagination_msg .= '' . t($i) . ''; - else: - $pagination_msg .= '' . t($i) . ''; - endif; - if ($i < $total_pages): - $pagination_msg .= '·'; - endif; - endfor; - elseif ($current_page < 9): - for ($i = 1; $i <= 10; $i++): - if ($i == $current_page): - $pagination_msg .= '' . t($i) . ''; - else: - $pagination_msg .= '' . t($i) . ''; - endif; - if ($i < 10): - $pagination_msg .= '·'; - endif; - endfor; - - $pagination_msg .= '…'; - $pagination_msg .= '' . t($total_pages - 1) . ''; - $pagination_msg .= '·'; - $pagination_msg .= '' . t($total_pages) . ''; - - elseif ($current_page > $total_pages - 8): - $pagination_msg .= '' . t(1) . ''; - $pagination_msg .= '·'; - $pagination_msg .= '' . t(2) . ''; - $pagination_msg .= '…'; - - for ($i = $total_pages - 9; $i <= $total_pages; $i++): - if ($i == $current_page): - $pagination_msg .= '' . t($i) . ''; - else: - $pagination_msg .= '' . t($i) . ''; - endif; - if ($i < $total_pages): - $pagination_msg .= '·'; - endif; - endfor; - - else: - $pagination_msg .= '' . t(1) . ''; - $pagination_msg .= '·'; - $pagination_msg .= '' . t(2) . ''; - $pagination_msg .= '…'; - - for ($i = $current_page - 5; $i <= $current_page + 5; $i++): - if ($i == $current_page): - $pagination_msg .= '' . t($i) . ''; - else: - $pagination_msg .= '' . t($i) . ''; - endif; - if ($i < $current_page + 5): - $pagination_msg .= '·'; - endif; - endfor; - - $pagination_msg .= '…'; - $pagination_msg .= '' . t($total_pages - 1) . ''; - $pagination_msg .= '·'; - $pagination_msg .= '' . t($total_pages) . ''; - endif; - endif; -?> - - \ No newline at end of file diff --git a/3.1/themes/greydragon/views/photo.html.php b/3.1/themes/greydragon/views/photo.html.php deleted file mode 100644 index 884e30a5..00000000 --- a/3.1/themes/greydragon/views/photo.html.php +++ /dev/null @@ -1,79 +0,0 @@ - -desc_allowbbcode): ?> - bb2html($item->description, 1); ?> - - description)); ?> - - -is_photometa_visible): ?> -' . $theme->thumb_info($item) . ''; ?> - - -
    - bb2html(html::purify($item->title), 1); ?> -
    -

    -
    - add_paginator("top"); ?> - photo_top() ?> - photo_descmode == "top") and ($_description)): ?> -
    - -
    - resize_top($item) ?> - - file_url() . '" class="g-sb-preview" '; ?> - - - - resize_width; ?> - parent()->children(); ?> - -
    - rand_key != $item->rand_key)); $i++): - ?> - "> - resize_img(array("id" => "g-photo-id-{$item->id}", "class" => "g-resize", "alt" => $_title)) ?> - - - photo_descmode == "overlay") and ($_description)): ?> - More - - - - - -
    - resize_bottom($item) ?> -
    - photo_descmode == "bottom") and ($_description)): ?> -
    - - add_paginator("bottom"); ?> - photo_bottom() ?> -
    diff --git a/3.1/themes/greydragon/views/rss_block.html.php b/3.1/themes/greydragon/views/rss_block.html.php deleted file mode 100644 index 4d30ce59..00000000 --- a/3.1/themes/greydragon/views/rss_block.html.php +++ /dev/null @@ -1,13 +0,0 @@ - - diff --git a/3.1/themes/greydragon/views/search.html.php b/3.1/themes/greydragon/views/search.html.php deleted file mode 100644 index 94fc170c..00000000 --- a/3.1/themes/greydragon/views/search.html.php +++ /dev/null @@ -1,43 +0,0 @@ - -
    -

    $q)) ?>

    - - - - add_paginator("top"); ?> -
      - - is_album() ? "g-album" : "g-photo" ?> - "> ?> - get_thumb_element($item) ?> - ?> - -
    - add_paginator("bottom"); ?> - -

     

    -

    %term", array("term" => $q)) ?>

    - - -
    \ No newline at end of file diff --git a/3.1/themes/greydragon/views/sidebar.html.php b/3.1/themes/greydragon/views/sidebar.html.php deleted file mode 100644 index 0cad333d..00000000 --- a/3.1/themes/greydragon/views/sidebar.html.php +++ /dev/null @@ -1,8 +0,0 @@ - - -sidebar_top() ?> -
     
    -page_subtype == "album") or ($theme->page_subtype == "photo") or ($theme->page_subtype == "movie") or ($theme->item())): ?> -sidebar_blocks() ?> - -sidebar_bottom() ?> diff --git a/3.1/themes/greydragon/views/tag_block.html.php b/3.1/themes/greydragon/views/tag_block.html.php deleted file mode 100644 index f9bc5886..00000000 --- a/3.1/themes/greydragon/views/tag_block.html.php +++ /dev/null @@ -1,27 +0,0 @@ - - -
    "> - -
    - \ No newline at end of file diff --git a/3.1/themes/greydragon/views/user_profile.html.php b/3.1/themes/greydragon/views/user_profile.html.php deleted file mode 100644 index b7d92f40..00000000 --- a/3.1/themes/greydragon/views/user_profile.html.php +++ /dev/null @@ -1,50 +0,0 @@ - - - -
    -

    $user->display_name())) ?>

    - - - - " - alt="display_name()) ?>" - class="g-avatar g-left" width="40" height="40" /> - - - -
    -

    title) ?>

    -
    - view ?> -
    -
    - -
    diff --git a/3.1/themes/three_nids/admin/helpers/three_nids_event.php b/3.1/themes/three_nids/admin/helpers/three_nids_event.php index c8a0db51..abb221fc 100644 --- a/3.1/themes/three_nids/admin/helpers/three_nids_event.php +++ b/3.1/themes/three_nids/admin/helpers/three_nids_event.php @@ -1,7 +1,7 @@