commit 10eb3340adefdf3916f15eb700aca8bb929f7dee Author: alazhar Date: Thu Jan 2 22:20:31 2020 +0700 first commit diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..df50810 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,340 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + 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 +convey 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..a1a53d7 --- /dev/null +++ b/README.txt @@ -0,0 +1,71 @@ +1- What is this? + * This is a Joomla! installation/upgrade package to version 3.x + * Joomla! Official site: http://www.joomla.org + * Joomla 3.1 version history - http://docs.joomla.org/Joomla_3.1_version_history + * Detailed changes in the Changelog: http://joomlacode.org/gf/project/joomla/scmsvn/?action=browse&path=/development/trunk/administrator/&view=log + +2- What is Joomla? + * Joomla is a Content Management System (CMS) which enables you to build Web sites and powerful online applications. + * It's a free and OpenSource software, distributed under the GNU General Public License version 2 or later + * This is a simple and powerful web server application and it requires a server with PHP and either MySQL, PostgreSQL, or SQL Server to run it. + More details here: http://www.joomla.org/about-joomla.html + +3- Is Joomla for you? + * Joomla is the right solution for any content web project: http://docs.joomla.org/Joomla_Is_it_for_me%3F + * See Features - http://www.joomla.org/core-features.html + * Try out our online demo: http://demo.joomla.org/ + +4- How to find a Joomla! translation? + * Repository of accredited language packs: http://community.joomla.org/translations.html + * Directory of non-accredited language packs (see above for accredited): http://extensions.joomla.org/extensions/languages/translations-for-joomla + +5- Learn Joomla! + * Read Getting Started with Joomla to find out the basics: http://docs.joomla.org/Getting_Started_with_Joomla! + * Before installing, read the beginners guide: http://docs.joomla.org/Beginners + +6- What are the limits of Joomla? + * Joomla sites can be extended in functionalities with Extensions that you can create (or download) to suite your needs. + * There are lots of ready made extensions that you can download and install. + * See the Joomla! Extensions Directory (JED): http://extensions.joomla.org + +7- Is it easy to change the layout display? + * The layout is controlled by templates that you can edit. + * There are lots of ready made templates that you can download. + +8- Ready to install Joomla? + * See minimum requirements here: http://www.joomla.org/technical-requirements.html + * How do you install Joomla! ? - http://docs.joomla.org/Installing_Joomla! + * Start your Joomla experience building your site with a local test server. + When ready it can be moved to an on-line hosting account of your choice. + See the tutorial: http://docs.joomla.org/Tutorial:Joomla_Local_install + +9- Updates are free! + * Always use the latest version: http://www.joomla.org/download.html + +10- Where can you get support and help? + * FAQ Frequently Asked Questions: http://docs.joomla.org/Category:FAQ + * Find the information you need: http://docs.joomla.org/Start_here + * Find help and other users: http://www.joomla.org/about-joomla/create-and-share.html + * Post questions at our forums: http://forum.joomla.org + * Joomla Resources Directory (JRD): http://resources.joomla.org/tos.html + +11- Do you already have a Joomla site that's not built with Joomla 3.x ? + * What's new in Joomla 3.x - http://www.joomla.org/3 + * What are the main differences from 2.5 to 3? Table of contents: http://docs.joomla.org/Differences_from_Joomla_2.5_to_Joomla_3.0 + * How to migrate from 2.5.x to 3.x? Tutorial: http://docs.joomla.org/Migrating_from_Joomla_2.5_to_Joomla_3.0 + * What are the main differences from 1.5 to 2.5? Table of contents: http://docs.joomla.org/Differences_from_Joomla_1.5_to_Joomla_2.5 + * How to migrate from 1.5.x to 3.x? Tutorial: http://docs.joomla.org/Migrating_from_Joomla_1.5_to_Joomla_3.0 + * Convert an existing Web site to Joomla - http://docs.joomla.org/How_to_Convert_an_existing_Web_site_to_a_Joomla!_Web_site + +12- Do you want to improve Joomla? + * How do you request a feature? http://docs.joomla.org/How_do_you_request_a_feature%3F + * How do you report a bug? http://docs.joomla.org/Filing_bugs_and_issues + * Get Involved: Joomla! is a community developed software. Join the community at http://www.joomla.org + * Are you a Developer? http://docs.joomla.org/Developers + * Are you a Web designer? http://docs.joomla.org/Web_designers + +Copyright: + * Copyright (C) 2005 - 2013 Open Source Matters. All rights reserved. + * Credits: http://docs.joomla.org/Joomla_3_Credits + * Distributed under the GNU General Public License version 2 or later + * See Licenses details at http://docs.joomla.org/Joomla_Licenses diff --git a/administrator/cache/index.html b/administrator/cache/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/cache/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/admin.php b/administrator/components/com_admin/admin.php new file mode 100644 index 0000000..2911a8d --- /dev/null +++ b/administrator/components/com_admin/admin.php @@ -0,0 +1,16 @@ +execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_admin/admin.xml b/administrator/components/com_admin/admin.xml new file mode 100644 index 0000000..04d26c9 --- /dev/null +++ b/administrator/components/com_admin/admin.xml @@ -0,0 +1,29 @@ + + + com_admin + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + + GNU General Public License version 2 or later; see + LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_ADMIN_XML_DESCRIPTION + + + + admin.php + controller.php + index.html + helpers + models + views + + + language/en-GB.com_admin.ini + language/en-GB.com_admin.sys.ini + + + diff --git a/administrator/components/com_admin/controller.php b/administrator/components/com_admin/controller.php new file mode 100644 index 0000000..d89d39d --- /dev/null +++ b/administrator/components/com_admin/controller.php @@ -0,0 +1,21 @@ + diff --git a/administrator/components/com_admin/controllers/profile.php b/administrator/components/com_admin/controllers/profile.php new file mode 100644 index 0000000..0130c46 --- /dev/null +++ b/administrator/components/com_admin/controllers/profile.php @@ -0,0 +1,89 @@ +id; + } + + /** + * Overrides parent save method to check the submitted passwords match. + * + * @return mixed Boolean or JError. + * @since 1.6 + */ + public function save($key = null, $urlVar = null) + { + $data = $this->input->post->get('jform', array(), 'array'); + + // TODO: JForm should really have a validation handler for this. + if (isset($data['password']) && isset($data['password2'])) + { + // Check the passwords match. + if ($data['password'] != $data['password2']) + { + $this->setMessage(JText::_('JLIB_USER_ERROR_PASSWORD_NOT_MATCH'), 'warning'); + $this->setRedirect(JRoute::_('index.php?option=com_admin&view=profile&layout=edit&id='.JFactory::getUser()->id, false)); + return false; + } + + unset($data['password2']); + } + + $return = parent::save(); + + if ($this->getTask() != 'apply') + { + // Redirect to the main page. + $this->setRedirect(JRoute::_('index.php', false)); + } + + return $return; + } + + /** + * Method to cancel an edit. + * + * @param string $key The name of the primary key of the URL variable. + * + * @return Boolean True if access level checks pass, false otherwise. + * @since 1.6 + */ + public function cancel($key = null) + { + $return = parent::cancel($key); + + // Redirect to the main page. + $this->setRedirect(JRoute::_('index.php', false)); + + return $return; + } +} diff --git a/administrator/components/com_admin/helpers/html/directory.php b/administrator/components/com_admin/helpers/html/directory.php new file mode 100644 index 0000000..aa24eb7 --- /dev/null +++ b/administrator/components/com_admin/helpers/html/directory.php @@ -0,0 +1,68 @@ +'. JText::_('COM_ADMIN_WRITABLE') .''; + } + else + { + return ''. JText::_('COM_ADMIN_UNWRITABLE') .''; + } + } + + /** + * Method to generate a message for a directory + * + * @param string $dir the directory + * @param boolean $message the message + * @param boolean $visible is the $dir visible? + * + * @return string html code + */ + public static function message($dir, $message, $visible=true) + { + if ($visible) + { + $output = $dir; + } + else + { + $output = ''; + } + if (empty($message)) + { + return $output; + } + else + { + return $output.' '.JText::_($message).''; + } + } +} diff --git a/administrator/components/com_admin/helpers/html/index.html b/administrator/components/com_admin/helpers/html/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/helpers/html/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/helpers/html/phpsetting.php b/administrator/components/com_admin/helpers/html/phpsetting.php new file mode 100644 index 0000000..cb75844 --- /dev/null +++ b/administrator/components/com_admin/helpers/html/phpsetting.php @@ -0,0 +1,92 @@ + diff --git a/administrator/components/com_admin/index.html b/administrator/components/com_admin/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/models/forms/index.html b/administrator/components/com_admin/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/models/forms/profile.xml b/administrator/components/com_admin/models/forms/profile.xml new file mode 100644 index 0000000..ddd7d7c --- /dev/null +++ b/administrator/components/com_admin/models/forms/profile.xml @@ -0,0 +1,139 @@ + +
+
+ + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
diff --git a/administrator/components/com_admin/models/help.php b/administrator/components/com_admin/models/help.php new file mode 100644 index 0000000..60f5d0c --- /dev/null +++ b/administrator/components/com_admin/models/help.php @@ -0,0 +1,186 @@ +help_search)) + { + $this->help_search = JFactory::getApplication()->input->getString('helpsearch'); + } + return $this->help_search; + } + + /** + * Method to get the page + * + * @return string The page + * + * @since 1.6 + */ + public function &getPage() + { + if (is_null($this->page)) + { + $page = JFactory::getApplication()->input->get('page', 'JHELP_START_HERE'); + $this->page = JHelp::createUrl($page); + } + return $this->page; + } + + /** + * Method to get the lang tag + * + * @return string lang iso tag + * + * @since 1.6 + */ + public function getLangTag() + { + if (is_null($this->lang_tag)) + { + $lang = JFactory::getLanguage(); + $this->lang_tag = $lang->getTag(); + + if (!is_dir(JPATH_BASE . '/help/' . $this->lang_tag)) + { + // Use english as fallback + $this->lang_tag = 'en-GB'; + } + + } + + return $this->lang_tag; + } + + /** + * Method to get the toc + * + * @return array Table of contents + */ + public function &getToc() + { + if (is_null($this->toc)) + { + // Get vars + $lang_tag = $this->getLangTag(); + $help_search = $this->getHelpSearch(); + + // Get Help files + jimport('joomla.filesystem.folder'); + $files = JFolder::files(JPATH_BASE . '/help/' . $lang_tag, '\.xml$|\.html$'); + $this->toc = array(); + foreach ($files as $file) + { + $buffer = file_get_contents(JPATH_BASE . '/help/' . $lang_tag . '/' . $file); + if (preg_match('#(.*?)#', $buffer, $m)) + { + $title = trim($m[1]); + if ($title) + { + // Translate the page title + $title = JText::_($title); + // strip the extension + $file = preg_replace('#\.xml$|\.html$#', '', $file); + if ($help_search) + { + if (JString::strpos(JString::strtolower(strip_tags($buffer)), JString::strtolower($help_search)) !== false) + { + // Add an item in the Table of Contents + $this->toc[$file] = $title; + } + } + else + { + // Add an item in the Table of Contents + $this->toc[$file] = $title; + } + } + } + } + // Sort the Table of Contents + asort($this->toc); + } + + return $this->toc; + } + + /** + * Method to get the latest version check + * + * @return string Latest Version Check URL + */ + public function &getLatestVersionCheck() + { + if (!$this->latest_version_check) + { + $override = 'http://help.joomla.org/proxy/index.php?option=com_help&keyref=Help{major}{minor}:Joomla_Version_{major}_{minor}_{maintenance}'; + $this->latest_version_check = JHelp::createUrl('JVERSION', false, $override); + } + + return $this->latest_version_check; + } +} diff --git a/administrator/components/com_admin/models/index.html b/administrator/components/com_admin/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/models/profile.php b/administrator/components/com_admin/models/profile.php new file mode 100644 index 0000000..985177a --- /dev/null +++ b/administrator/components/com_admin/models/profile.php @@ -0,0 +1,130 @@ +loadForm('com_admin.profile', 'profile', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + if (!JComponentHelper::getParams('com_users')->get('change_login_name')) + { + $form->setFieldAttribute('username', 'required', 'false'); + $form->setFieldAttribute('username', 'readonly', 'true'); + $form->setFieldAttribute('username', 'description', 'COM_ADMIN_USER_FIELD_NOCHANGE_USERNAME_DESC'); + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_users.edit.user.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + } + + // Load the users plugins. + JPluginHelper::importPlugin('user'); + + $this->preprocessData('com_admin.profile', $data); + + return $data; + } + + /** + * Method to get a single record. + * + * @return mixed Object on success, false on failure. + * + * @since 1.6 + */ + public function getItem($pk = null) + { + $user = JFactory::getUser(); + + return parent::getItem($user->get('id')); + } + + /** + * Method to save the form data. + * + * @param array $data The form data. + * + * @return boolean True on success. + * + * @since 1.6 + */ + public function save($data) + { + $user = JFactory::getUser(); + + unset($data['id']); + unset($data['groups']); + unset($data['sendEmail']); + unset($data['block']); + + // Bind the data. + if (!$user->bind($data)) + { + $this->setError($user->getError()); + + return false; + } + + $user->groups = null; + + // Store the data. + if (!$user->save()) + { + $this->setError($user->getError()); + + return false; + } + + $this->setState('user.id', $user->id); + + return true; + } +} diff --git a/administrator/components/com_admin/models/sysinfo.php b/administrator/components/com_admin/models/sysinfo.php new file mode 100644 index 0000000..c96207b --- /dev/null +++ b/administrator/components/com_admin/models/sysinfo.php @@ -0,0 +1,315 @@ +php_settings)) + { + $this->php_settings = array(); + $this->php_settings['safe_mode'] = ini_get('safe_mode') == '1'; + $this->php_settings['display_errors'] = ini_get('display_errors') == '1'; + $this->php_settings['short_open_tag'] = ini_get('short_open_tag') == '1'; + $this->php_settings['file_uploads'] = ini_get('file_uploads') == '1'; + $this->php_settings['magic_quotes_gpc'] = ini_get('magic_quotes_gpc') == '1'; + $this->php_settings['register_globals'] = ini_get('register_globals') == '1'; + $this->php_settings['output_buffering'] = (bool) ini_get('output_buffering'); + $this->php_settings['open_basedir'] = ini_get('open_basedir'); + $this->php_settings['session.save_path'] = ini_get('session.save_path'); + $this->php_settings['session.auto_start'] = ini_get('session.auto_start'); + $this->php_settings['disable_functions'] = ini_get('disable_functions'); + $this->php_settings['xml'] = extension_loaded('xml'); + $this->php_settings['zlib'] = extension_loaded('zlib'); + $this->php_settings['zip'] = function_exists('zip_open') && function_exists('zip_read'); + $this->php_settings['mbstring'] = extension_loaded('mbstring'); + $this->php_settings['iconv'] = function_exists('iconv'); + } + + return $this->php_settings; + } + + /** + * Method to get the config + * + * @return array config values + * + * @since 1.6 + */ + public function &getConfig() + { + if (is_null($this->config)) + { + $registry = new JRegistry(new JConfig); + $this->config = $registry->toArray(); + $hidden = array('host', 'user', 'password', 'ftp_user', 'ftp_pass', 'smtpuser', 'smtppass'); + foreach ($hidden as $key) + { + $this->config[$key] = 'xxxxxx'; + } + } + + return $this->config; + } + + /** + * Method to get the system information + * + * @return array system information values + * + * @since 1.6 + */ + public function &getInfo() + { + if (is_null($this->info)) + { + $this->info = array(); + $version = new JVersion; + $platform = new JPlatform; + $db = JFactory::getDbo(); + if (isset($_SERVER['SERVER_SOFTWARE'])) + { + $sf = $_SERVER['SERVER_SOFTWARE']; + } + else { + $sf = getenv('SERVER_SOFTWARE'); + } + $this->info['php'] = php_uname(); + $this->info['dbversion'] = $db->getVersion(); + $this->info['dbcollation'] = $db->getCollation(); + $this->info['phpversion'] = phpversion(); + $this->info['server'] = $sf; + $this->info['sapi_name'] = php_sapi_name(); + $this->info['version'] = $version->getLongVersion(); + $this->info['platform'] = $platform->getLongVersion(); + $this->info['useragent'] = $_SERVER['HTTP_USER_AGENT']; + } + return $this->info; + } + + /** + * Method to get the PHP info + * + * @return string PHP info + * + * @since 1.6 + */ + public function &getPHPInfo() + { + if (is_null($this->php_info)) + { + ob_start(); + date_default_timezone_set('UTC'); + phpinfo(INFO_GENERAL | INFO_CONFIGURATION | INFO_MODULES); + $phpinfo = ob_get_contents(); + ob_end_clean(); + preg_match_all('#]*>(.*)#siU', $phpinfo, $output); + $output = preg_replace('#]*>#', '', $output[1][0]); + $output = preg_replace('#(\w),(\w)#', '\1, \2', $output); + $output = preg_replace('#
#', '', $output); + $output = str_replace('
', '', $output); + $output = preg_replace('#
(.*)<\/tr>#', '$1', $output); + $output = str_replace('
', '', $output); + $output = str_replace('', '', $output); + $this->php_info = $output; + } + + return $this->php_info; + } + + /** + * Method to get the directory states + * + * @return array States of directories + * + * @since 1.6 + */ + public function getDirectory() + { + if (is_null($this->directories)) + { + $this->directories = array(); + + $registry = JFactory::getConfig(); + $cparams = JComponentHelper::getParams('com_media'); + + $this->_addDirectory('administrator/components', JPATH_ADMINISTRATOR . '/components'); + $this->_addDirectory('administrator/language', JPATH_ADMINISTRATOR . '/language'); + + // List all admin languages + $admin_langs = new DirectoryIterator(JPATH_ADMINISTRATOR . '/language'); + foreach ($admin_langs as $folder) + { + if (!$folder->isDir() || $folder->isDot()) + { + continue; + } + + $this->_addDirectory('administrator/language/' . $folder->getFilename(), JPATH_ADMINISTRATOR . '/language/' . $folder->getFilename()); + } + + // List all manifests folders + $manifests = new DirectoryIterator(JPATH_ADMINISTRATOR . '/manifests'); + foreach ($manifests as $folder) + { + if (!$folder->isDir() || $folder->isDot()) + { + continue; + } + + $this->_addDirectory('administrator/manifests/' . $folder->getFilename(), JPATH_ADMINISTRATOR . '/manifests/' . $folder->getFilename()); + } + + $this->_addDirectory('administrator/modules', JPATH_ADMINISTRATOR . '/modules'); + $this->_addDirectory('administrator/templates', JPATH_THEMES); + + $this->_addDirectory('components', JPATH_SITE . '/components'); + + $this->_addDirectory($cparams->get('image_path'), JPATH_SITE . '/' . $cparams->get('image_path')); + + // List all images folders + $image_folders = new DirectoryIterator(JPATH_SITE . '/' . $cparams->get('image_path')); + foreach ($image_folders as $folder) + { + if (!$folder->isDir() || $folder->isDot()) + { + continue; + } + + $this->_addDirectory('images/' . $folder->getFilename(), JPATH_SITE . '/' . $cparams->get('image_path') . '/' . $folder->getFilename()); + } + + $this->_addDirectory('language', JPATH_SITE . '/language'); + + // List all site languages + $site_langs = new DirectoryIterator(JPATH_SITE . '/language'); + foreach ($site_langs as $folder) + { + if (!$folder->isDir() || $folder->isDot()) + { + continue; + } + + $this->_addDirectory('language/' . $folder->getFilename(), JPATH_SITE . '/language/' . $folder->getFilename()); + } + + $this->_addDirectory('libraries', JPATH_LIBRARIES); + + $this->_addDirectory('media', JPATH_SITE . '/media'); + $this->_addDirectory('modules', JPATH_SITE . '/modules'); + $this->_addDirectory('plugins', JPATH_PLUGINS); + + $plugin_groups = new DirectoryIterator(JPATH_SITE . '/plugins'); + foreach ($plugin_groups as $folder) + { + if (!$folder->isDir() || $folder->isDot()) + { + continue; + } + + $this->_addDirectory('plugins/' . $folder->getFilename(), JPATH_PLUGINS . '/' . $folder->getFilename()); + } + + $this->_addDirectory('templates', JPATH_SITE . '/templates'); + $this->_addDirectory('configuration.php', JPATH_CONFIGURATION . '/configuration.php'); + $this->_addDirectory('cache', JPATH_SITE . '/cache', 'COM_ADMIN_CACHE_DIRECTORY'); + $this->_addDirectory('administrator/cache', JPATH_CACHE, 'COM_ADMIN_CACHE_DIRECTORY'); + + $this->_addDirectory($registry->get('log_path', JPATH_ROOT . '/log'), $registry->get('log_path', JPATH_ROOT . '/log'), 'COM_ADMIN_LOG_DIRECTORY'); + $this->_addDirectory($registry->get('tmp_path', JPATH_ROOT . '/tmp'), $registry->get('tmp_path', JPATH_ROOT . '/tmp'), 'COM_ADMIN_TEMP_DIRECTORY'); + } + return $this->directories; + } + + /** + * Method to add a directory + * + * @return void + * @since 1.6 + */ + private function _addDirectory($name, $path, $message = '') + { + $this->directories[$name] = array('writable' => is_writable($path), 'message' => $message); + } + + /** + * Method to get the editor + * + * @return string The default editor + * + * @note: has to be removed (it is present in the config...) + * + * @since 1.6 + */ + public function &getEditor() + { + if (is_null($this->editor)) + { + $config = JFactory::getConfig(); + $this->editor = $config->get('editor'); + } + return $this->editor; + } +} diff --git a/administrator/components/com_admin/script.php b/administrator/components/com_admin/script.php new file mode 100644 index 0000000..849cc16 --- /dev/null +++ b/administrator/components/com_admin/script.php @@ -0,0 +1,673 @@ +deleteUnexistingFiles(); + $this->updateManifestCaches(); + $this->updateDatabase(); + } + + protected function updateDatabase() + { + $db = JFactory::getDbo(); + if (substr($db->name, 0, 5) == 'mysql') + { + $db->setQuery('SHOW ENGINES'); + $results = $db->loadObjectList(); + if ($db->getErrorNum()) + { + echo JText::sprintf('JLIB_DATABASE_ERROR_FUNCTION_FAILED', $db->getErrorNum(), $db->getErrorMsg()) . '
'; + return; + } + foreach ($results as $result) + { + if ($result->Support == 'DEFAULT') + { + $db->setQuery('ALTER TABLE #__update_sites_extensions ENGINE = ' . $result->Engine); + $db->execute(); + if ($db->getErrorNum()) + { + echo JText::sprintf('JLIB_DATABASE_ERROR_FUNCTION_FAILED', $db->getErrorNum(), $db->getErrorMsg()) . '
'; + return; + } + break; + } + } + } + } + + protected function updateManifestCaches() + { + $extensions = array(); + // Components + + //`type`, `element`, `folder`, `client_id` + $extensions[] = array('component', 'com_mailto', '', 0); + $extensions[] = array('component', 'com_wrapper', '', 0); + $extensions[] = array('component', 'com_admin', '', 1); + $extensions[] = array('component', 'com_banners', '', 1); + $extensions[] = array('component', 'com_cache', '', 1); + $extensions[] = array('component', 'com_categories', '', 1); + $extensions[] = array('component', 'com_checkin', '', 1); + $extensions[] = array('component', 'com_contact', '', 1); + $extensions[] = array('component', 'com_cpanel', '', 1); + $extensions[] = array('component', 'com_installer', '', 1); + $extensions[] = array('component', 'com_languages', '', 1); + $extensions[] = array('component', 'com_login', '', 1); + $extensions[] = array('component', 'com_media', '', 1); + $extensions[] = array('component', 'com_menus', '', 1); + $extensions[] = array('component', 'com_messages', '', 1); + $extensions[] = array('component', 'com_modules', '', 1); + $extensions[] = array('component', 'com_newsfeeds', '', 1); + $extensions[] = array('component', 'com_plugins', '', 1); + $extensions[] = array('component', 'com_search', '', 1); + $extensions[] = array('component', 'com_templates', '', 1); + $extensions[] = array('component', 'com_weblinks', '', 1); + $extensions[] = array('component', 'com_content', '', 1); + $extensions[] = array('component', 'com_config', '', 1); + $extensions[] = array('component', 'com_redirect', '', 1); + $extensions[] = array('component', 'com_users', '', 1); + $extensions[] = array('component', 'com_tags', '', 1); + + // Libraries + $extensions[] = array('library', 'phpmailer', '', 0); + $extensions[] = array('library', 'simplepie', '', 0); + $extensions[] = array('library', 'phputf8', '', 0); + $extensions[] = array('library', 'joomla', '', 0); + $extensions[] = array('library', 'idna_convert', '', 0); + + // Modules site + // Site + $extensions[] = array('module', 'mod_articles_archive', '', 0); + $extensions[] = array('module', 'mod_articles_latest', '', 0); + $extensions[] = array('module', 'mod_articles_popular', '', 0); + $extensions[] = array('module', 'mod_banners', '', 0); + $extensions[] = array('module', 'mod_breadcrumbs', '', 0); + $extensions[] = array('module', 'mod_custom', '', 0); + $extensions[] = array('module', 'mod_feed', '', 0); + $extensions[] = array('module', 'mod_footer', '', 0); + $extensions[] = array('module', 'mod_login', '', 0); + $extensions[] = array('module', 'mod_menu', '', 0); + $extensions[] = array('module', 'mod_articles_news', '', 0); + $extensions[] = array('module', 'mod_random_image', '', 0); + $extensions[] = array('module', 'mod_related_items', '', 0); + $extensions[] = array('module', 'mod_search', '', 0); + $extensions[] = array('module', 'mod_stats', '', 0); + $extensions[] = array('module', 'mod_syndicate', '', 0); + $extensions[] = array('module', 'mod_users_latest', '', 0); + $extensions[] = array('module', 'mod_weblinks', '', 0); + $extensions[] = array('module', 'mod_whosonline', '', 0); + $extensions[] = array('module', 'mod_wrapper', '', 0); + $extensions[] = array('module', 'mod_articles_category', '', 0); + $extensions[] = array('module', 'mod_articles_categories', '', 0); + $extensions[] = array('module', 'mod_languages', '', 0); + $extensions[] = array('module', 'mod_tags_popular', '', 0); + $extensions[] = array('module', 'mod_tags_similar', '', 0); + + // Administrator + $extensions[] = array('module', 'mod_custom', '', 1); + $extensions[] = array('module', 'mod_feed', '', 1); + $extensions[] = array('module', 'mod_latest', '', 1); + $extensions[] = array('module', 'mod_logged', '', 1); + $extensions[] = array('module', 'mod_login', '', 1); + $extensions[] = array('module', 'mod_menu', '', 1); + $extensions[] = array('module', 'mod_popular', '', 1); + $extensions[] = array('module', 'mod_quickicon', '', 1); + $extensions[] = array('module', 'mod_stats_admin', '', 1); + $extensions[] = array('module', 'mod_status', '', 1); + $extensions[] = array('module', 'mod_submenu', '', 1); + $extensions[] = array('module', 'mod_title', '', 1); + $extensions[] = array('module', 'mod_toolbar', '', 1); + $extensions[] = array('module', 'mod_multilangstatus', '', 1); + + // Plug-ins + $extensions[] = array('plugin', 'gmail', 'authentication', 0); + $extensions[] = array('plugin', 'joomla', 'authentication', 0); + $extensions[] = array('plugin', 'ldap', 'authentication', 0); + $extensions[] = array('plugin', 'emailcloak', 'content', 0); + $extensions[] = array('plugin', 'loadmodule', 'content', 0); + $extensions[] = array('plugin', 'pagebreak', 'content', 0); + $extensions[] = array('plugin', 'pagenavigation', 'content', 0); + $extensions[] = array('plugin', 'vote', 'content', 0); + $extensions[] = array('plugin', 'codemirror', 'editors', 0); + $extensions[] = array('plugin', 'none', 'editors', 0); + $extensions[] = array('plugin', 'tinymce', 'editors', 0); + $extensions[] = array('plugin', 'article', 'editors-xtd', 0); + $extensions[] = array('plugin', 'image', 'editors-xtd', 0); + $extensions[] = array('plugin', 'pagebreak', 'editors-xtd', 0); + $extensions[] = array('plugin', 'readmore', 'editors-xtd', 0); + $extensions[] = array('plugin', 'categories', 'search', 0); + $extensions[] = array('plugin', 'contacts', 'search', 0); + $extensions[] = array('plugin', 'content', 'search', 0); + $extensions[] = array('plugin', 'newsfeeds', 'search', 0); + $extensions[] = array('plugin', 'weblinks', 'search', 0); + $extensions[] = array('plugin', 'languagefilter', 'system', 0); + $extensions[] = array('plugin', 'p3p', 'system', 0); + $extensions[] = array('plugin', 'cache', 'system', 0); + $extensions[] = array('plugin', 'debug', 'system', 0); + $extensions[] = array('plugin', 'log', 'system', 0); + $extensions[] = array('plugin', 'redirect', 'system', 0); + $extensions[] = array('plugin', 'remember', 'system', 0); + $extensions[] = array('plugin', 'sef', 'system', 0); + $extensions[] = array('plugin', 'logout', 'system', 0); + $extensions[] = array('plugin', 'contactcreator', 'user', 0); + $extensions[] = array('plugin', 'joomla', 'user', 0); + $extensions[] = array('plugin', 'profile', 'user', 0); + $extensions[] = array('plugin', 'joomla', 'extension', 0); + $extensions[] = array('plugin', 'joomla', 'content', 0); + $extensions[] = array('plugin', 'languagecode', 'system', 0); + $extensions[] = array('plugin', 'joomlaupdate', 'quickicon', 0); + $extensions[] = array('plugin', 'extensionupdate', 'quickicon', 0); + $extensions[] = array('plugin', 'recaptcha', 'captcha', 0); + $extensions[] = array('plugin', 'categories', 'finder', 0); + $extensions[] = array('plugin', 'contacts', 'finder', 0); + $extensions[] = array('plugin', 'content', 'finder', 0); + $extensions[] = array('plugin', 'newsfeeds', 'finder', 0); + $extensions[] = array('plugin', 'weblinks', 'finder', 0); + $extensions[] = array('plugin', 'tags', 'finder', 0); + + // Templates + $extensions[] = array('template', 'beez3', '', 0); + $extensions[] = array('template', 'hathor', '', 1); + $extensions[] = array('template', 'protostar', '', 0); + $extensions[] = array('template', 'isis', '', 1); + + // Languages + $extensions[] = array('language', 'en-GB', '', 0); + $extensions[] = array('language', 'en-GB', '', 1); + + // Files + $extensions[] = array('file', 'joomla', '', 0); + + // Packages + // None in core at this time + + // Attempt to refresh manifest caches + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('*') + ->from('#__extensions'); + foreach ($extensions as $extension) + { + $query->where('type=' . $db->quote($extension[0]) . ' AND element=' . $db->quote($extension[1]) . ' AND folder=' . $db->quote($extension[2]) . ' AND client_id=' . $extension[3], 'OR'); + } + $db->setQuery($query); + $extensions = $db->loadObjectList(); + $installer = new JInstaller; + // Check for a database error. + if ($db->getErrorNum()) + { + echo JText::sprintf('JLIB_DATABASE_ERROR_FUNCTION_FAILED', $db->getErrorNum(), $db->getErrorMsg()) . '
'; + return; + } + foreach ($extensions as $extension) + { + if (!$installer->refreshManifestCache($extension->extension_id)) + { + echo JText::sprintf('FILES_JOOMLA_ERROR_MANIFEST', $extension->type, $extension->element, $extension->name, $extension->client_id) . '
'; + } + } + } + + public function deleteUnexistingFiles() + { + $files = array( + '/libraries/cms/cmsloader.php', + '/libraries/joomla/form/fields/templatestyle.php', + '/libraries/joomla/form/fields/user.php', + '/libraries/joomla/form/fields/menu.php', + '/libraries/joomla/form/fields/helpsite.php', + '/administrator/components/com_admin/sql/updates/mysql/1.7.0.sql', + '/administrator/components/com_admin/sql/updates/sqlsrv/2.5.2-2012-03-05.sql', + '/administrator/components/com_admin/sql/updates/sqlsrv/2.5.3-2012-03-13.sql', + '/administrator/components/com_admin/sql/updates/sqlsrv/index.html', + '/administrator/components/com_users/controllers/config.php', + '/administrator/language/en-GB/en-GB.plg_system_finder.ini', + '/administrator/language/en-GB/en-GB.plg_system_finder.sys.ini', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/advhr/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/advimage/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/advlink/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/advlist/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/autolink/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/autoresize/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/autosave/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/bbcode/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/contextmenu/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/directionality/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/emotions/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/fullpage/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/fullscreen/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/iespell/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/inlinepopups/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/insertdatetime/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/layer/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/lists/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/media/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/nonbreaking/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/noneditable/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/pagebreak/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/paste/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/preview/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/print/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/save/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/searchreplace/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/spellchecker/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/style/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/tabfocus/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/table/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/template/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/visualchars/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/wordcount/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/themes/advanced/editor_template_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/themes/simple/editor_template_src.js', + '/media/editors/tinymce/jscripts/tiny_mce/tiny_mce_src.js', + '/media/com_finder/images/calendar.png', + '/media/com_finder/images/mime/index.html', + '/media/com_finder/images/mime/pdf.png', + '/components/com_media/controller.php', + '/components/com_media/helpers/index.html', + '/components/com_media/helpers/media.php', + // Joomla 3.0 + '/administrator/components/com_admin/sql/updates/mysql/1.7.0-2011-06-06-2.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.0-2011-06-06.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.0.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.1-2011-09-15-2.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.1-2011-09-15-3.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.1-2011-09-15-4.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.1-2011-09-15.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.1-2011-09-17.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.1-2011-09-20.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.3-2011-10-15.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.3-2011-10-19.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.3-2011-11-10.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.4-2011-11-19.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.4-2011-11-23.sql', + '/administrator/components/com_admin/sql/updates/mysql/1.7.4-2011-12-12.sql', + '/administrator/components/com_admin/views/sysinfo/tmpl/default_navigation.php', + '/administrator/components/com_categories/config.xml', + '/administrator/components/com_categories/helpers/categoriesadministrator.php', + '/administrator/components/com_contact/elements/contact.php', + '/administrator/components/com_contact/elements/index.html', + '/administrator/components/com_content/elements/article.php', + '/administrator/components/com_content/elements/author.php', + '/administrator/components/com_content/elements/index.html', + '/administrator/components/com_installer/models/fields/client.php', + '/administrator/components/com_installer/models/fields/group.php', + '/administrator/components/com_installer/models/fields/index.html', + '/administrator/components/com_installer/models/fields/search.php', + '/administrator/components/com_installer/models/fields/type.php', + '/administrator/components/com_installer/models/forms/index.html', + '/administrator/components/com_installer/models/forms/manage.xml', + '/administrator/components/com_installer/views/install/tmpl/default_form.php', + '/administrator/components/com_installer/views/manage/tmpl/default_filter.php', + '/administrator/components/com_languages/views/installed/tmpl/default_ftp.php', + '/administrator/components/com_languages/views/installed/tmpl/default_navigation.php', + '/administrator/components/com_modules/models/fields/index.html', + '/administrator/components/com_modules/models/fields/moduleorder.php', + '/administrator/components/com_modules/models/fields/moduleposition.php', + '/administrator/components/com_newsfeeds/elements/index.html', + '/administrator/components/com_newsfeeds/elements/newsfeed.php', + '/administrator/components/com_templates/views/prevuuw/index.html', + '/administrator/components/com_templates/views/prevuuw/tmpl/default.php', + '/administrator/components/com_templates/views/prevuuw/tmpl/index.html', + '/administrator/components/com_templates/views/prevuuw/view.html.php', + '/administrator/includes/menu.php', + '/administrator/includes/router.php', + '/administrator/manifests/packages/pkg_joomla.xml', + '/administrator/modules/mod_submenu/helper.php', + '/administrator/templates/hathor/css/ie6.css', + '/administrator/templates/hathor/html/mod_submenu/index.html', + '/administrator/templates/hathor/html/mod_submenu/default.php', + '/components/com_media/controller.php', + '/components/com_media/helpers/index.html', + '/components/com_media/helpers/media.php', + '/includes/menu.php', + '/includes/pathway.php', + '/includes/router.php', + '/language/en-GB/en-GB.pkg_joomla.sys.ini', + '/libraries/cms/controller/index.html', + '/libraries/cms/controller/legacy.php', + '/libraries/cms/model/index.html', + '/libraries/cms/model/legacy.php', + '/libraries/cms/schema/changeitemmysql.php', + '/libraries/cms/schema/changeitemsqlazure.php', + '/libraries/cms/schema/changeitemsqlsrv.php', + '/libraries/cms/view/index.html', + '/libraries/cms/view/legacy.php', + '/libraries/joomla/application/application.php', + '/libraries/joomla/application/categories.php', + '/libraries/joomla/application/cli/daemon.php', + '/libraries/joomla/application/cli/index.html', + '/libraries/joomla/application/component/controller.php', + '/libraries/joomla/application/component/controlleradmin.php', + '/libraries/joomla/application/component/controllerform.php', + '/libraries/joomla/application/component/helper.php', + '/libraries/joomla/application/component/index.html', + '/libraries/joomla/application/component/model.php', + '/libraries/joomla/application/component/modeladmin.php', + '/libraries/joomla/application/component/modelform.php', + '/libraries/joomla/application/component/modelitem.php', + '/libraries/joomla/application/component/modellist.php', + '/libraries/joomla/application/component/view.php', + '/libraries/joomla/application/helper.php', + '/libraries/joomla/application/input.php', + '/libraries/joomla/application/input/cli.php', + '/libraries/joomla/application/input/cookie.php', + '/libraries/joomla/application/input/files.php', + '/libraries/joomla/application/input/index.html', + '/libraries/joomla/application/menu.php', + '/libraries/joomla/application/module/helper.php', + '/libraries/joomla/application/module/index.html', + '/libraries/joomla/application/pathway.php', + '/libraries/joomla/application/web/webclient.php', + '/libraries/joomla/base/node.php', + '/libraries/joomla/base/object.php', + '/libraries/joomla/base/observable.php', + '/libraries/joomla/base/observer.php', + '/libraries/joomla/base/tree.php', + '/libraries/joomla/cache/storage/eaccelerator.php', + '/libraries/joomla/cache/storage/helpers/helper.php', + '/libraries/joomla/cache/storage/helpers/index.html', + '/libraries/joomla/database/database/index.html', + '/libraries/joomla/database/database/mysql.php', + '/libraries/joomla/database/database/mysqlexporter.php', + '/libraries/joomla/database/database/mysqli.php', + '/libraries/joomla/database/database/mysqliexporter.php', + '/libraries/joomla/database/database/mysqliimporter.php', + '/libraries/joomla/database/database/mysqlimporter.php', + '/libraries/joomla/database/database/mysqliquery.php', + '/libraries/joomla/database/database/mysqlquery.php', + '/libraries/joomla/database/database/sqlazure.php', + '/libraries/joomla/database/database/sqlazurequery.php', + '/libraries/joomla/database/database/sqlsrv.php', + '/libraries/joomla/database/database/sqlsrvquery.php', + '/libraries/joomla/database/exception.php', + '/libraries/joomla/database/table.php', + '/libraries/joomla/database/table/asset.php', + '/libraries/joomla/database/table/category.php', + '/libraries/joomla/database/table/content.php', + '/libraries/joomla/database/table/extension.php', + '/libraries/joomla/database/table/index.html', + '/libraries/joomla/database/table/language.php', + '/libraries/joomla/database/table/menu.php', + '/libraries/joomla/database/table/menutype.php', + '/libraries/joomla/database/table/module.php', + '/libraries/joomla/database/table/session.php', + '/libraries/joomla/database/table/update.php', + '/libraries/joomla/database/table/user.php', + '/libraries/joomla/database/table/usergroup.php', + '/libraries/joomla/database/table/viewlevel.php', + '/libraries/joomla/database/tablenested.php', + '/libraries/joomla/environment/request.php', + '/libraries/joomla/environment/uri.php', + '/libraries/joomla/error/error.php', + '/libraries/joomla/error/exception.php', + '/libraries/joomla/error/index.html', + '/libraries/joomla/error/log.php', + '/libraries/joomla/error/profiler.php', + '/libraries/joomla/filesystem/archive.php', + '/libraries/joomla/filesystem/archive/bzip2.php', + '/libraries/joomla/filesystem/archive/gzip.php', + '/libraries/joomla/filesystem/archive/index.html', + '/libraries/joomla/filesystem/archive/tar.php', + '/libraries/joomla/filesystem/archive/zip.php', + '/libraries/joomla/form/fields/category.php', + '/libraries/joomla/form/fields/componentlayout.php', + '/libraries/joomla/form/fields/contentlanguage.php', + '/libraries/joomla/form/fields/editor.php', + '/libraries/joomla/form/fields/editors.php', + '/libraries/joomla/form/fields/media.php', + '/libraries/joomla/form/fields/menuitem.php', + '/libraries/joomla/form/fields/modulelayout.php', + '/libraries/joomla/html/editor.php', + '/libraries/joomla/html/html/access.php', + '/libraries/joomla/html/html/batch.php', + '/libraries/joomla/html/html/behavior.php', + '/libraries/joomla/html/html/category.php', + '/libraries/joomla/html/html/content.php', + '/libraries/joomla/html/html/contentlanguage.php', + '/libraries/joomla/html/html/date.php', + '/libraries/joomla/html/html/email.php', + '/libraries/joomla/html/html/form.php', + '/libraries/joomla/html/html/grid.php', + '/libraries/joomla/html/html/image.php', + '/libraries/joomla/html/html/index.html', + '/libraries/joomla/html/html/jgrid.php', + '/libraries/joomla/html/html/list.php', + '/libraries/joomla/html/html/menu.php', + '/libraries/joomla/html/html/number.php', + '/libraries/joomla/html/html/rules.php', + '/libraries/joomla/html/html/select.php', + '/libraries/joomla/html/html/sliders.php', + '/libraries/joomla/html/html/string.php', + '/libraries/joomla/html/html/tabs.php', + '/libraries/joomla/html/html/tel.php', + '/libraries/joomla/html/html/user.php', + '/libraries/joomla/html/pagination.php', + '/libraries/joomla/html/pane.php', + '/libraries/joomla/html/parameter.php', + '/libraries/joomla/html/parameter/element.php', + '/libraries/joomla/html/parameter/element/calendar.php', + '/libraries/joomla/html/parameter/element/category.php', + '/libraries/joomla/html/parameter/element/componentlayouts.php', + '/libraries/joomla/html/parameter/element/contentlanguages.php', + '/libraries/joomla/html/parameter/element/editors.php', + '/libraries/joomla/html/parameter/element/filelist.php', + '/libraries/joomla/html/parameter/element/folderlist.php', + '/libraries/joomla/html/parameter/element/helpsites.php', + '/libraries/joomla/html/parameter/element/hidden.php', + '/libraries/joomla/html/parameter/element/imagelist.php', + '/libraries/joomla/html/parameter/element/index.html', + '/libraries/joomla/html/parameter/element/languages.php', + '/libraries/joomla/html/parameter/element/list.php', + '/libraries/joomla/html/parameter/element/menu.php', + '/libraries/joomla/html/parameter/element/menuitem.php', + '/libraries/joomla/html/parameter/element/modulelayouts.php', + '/libraries/joomla/html/parameter/element/password.php', + '/libraries/joomla/html/parameter/element/radio.php', + '/libraries/joomla/html/parameter/element/spacer.php', + '/libraries/joomla/html/parameter/element/sql.php', + '/libraries/joomla/html/parameter/element/templatestyle.php', + '/libraries/joomla/html/parameter/element/text.php', + '/libraries/joomla/html/parameter/element/textarea.php', + '/libraries/joomla/html/parameter/element/timezones.php', + '/libraries/joomla/html/parameter/element/usergroup.php', + '/libraries/joomla/html/parameter/index.html', + '/libraries/joomla/html/toolbar.php', + '/libraries/joomla/html/toolbar/button.php', + '/libraries/joomla/html/toolbar/button/confirm.php', + '/libraries/joomla/html/toolbar/button/custom.php', + '/libraries/joomla/html/toolbar/button/help.php', + '/libraries/joomla/html/toolbar/button/index.html', + '/libraries/joomla/html/toolbar/button/link.php', + '/libraries/joomla/html/toolbar/button/popup.php', + '/libraries/joomla/html/toolbar/button/separator.php', + '/libraries/joomla/html/toolbar/button/standard.php', + '/libraries/joomla/html/toolbar/index.html', + '/libraries/joomla/image/filters/brightness.php', + '/libraries/joomla/image/filters/contrast.php', + '/libraries/joomla/image/filters/edgedetect.php', + '/libraries/joomla/image/filters/emboss.php', + '/libraries/joomla/image/filters/grayscale.php', + '/libraries/joomla/image/filters/index.html', + '/libraries/joomla/image/filters/negate.php', + '/libraries/joomla/image/filters/sketchy.php', + '/libraries/joomla/image/filters/smooth.php', + '/libraries/joomla/language/help.php', + '/libraries/joomla/language/latin_transliterate.php', + '/libraries/joomla/log/logexception.php', + '/libraries/joomla/log/loggers/database.php', + '/libraries/joomla/log/loggers/echo.php', + '/libraries/joomla/log/loggers/formattedtext.php', + '/libraries/joomla/log/loggers/index.html', + '/libraries/joomla/log/loggers/messagequeue.php', + '/libraries/joomla/log/loggers/syslog.php', + '/libraries/joomla/log/loggers/w3c.php', + '/libraries/joomla/methods.php', + '/libraries/joomla/session/storage/eaccelerator.php', + '/libraries/joomla/string/stringnormalize.php', + '/libraries/joomla/utilities/date.php', + '/libraries/joomla/utilities/simplecrypt.php', + '/libraries/joomla/utilities/simplexml.php', + '/libraries/joomla/utilities/string.php', + '/libraries/joomla/utilities/xmlelement.php', + '/media/plg_quickicon_extensionupdate/extensionupdatecheck.js', + '/media/plg_quickicon_joomlaupdate/jupdatecheck.js', + // Joomla! 3.1 + '/libraries/joomla/form/rules/boolean.php', + '/libraries/joomla/form/rules/color.php', + '/libraries/joomla/form/rules/email.php', + '/libraries/joomla/form/rules/equals.php', + '/libraries/joomla/form/rules/index.html', + '/libraries/joomla/form/rules/options.php', + '/libraries/joomla/form/rules/rules.php', + '/libraries/joomla/form/rules/tel.php', + '/libraries/joomla/form/rules/url.php', + '/libraries/joomla/form/rules/username.php', + '/libraries/joomla/html/access.php', + '/libraries/joomla/html/behavior.php', + '/libraries/joomla/html/content.php', + '/libraries/joomla/html/date.php', + '/libraries/joomla/html/email.php', + '/libraries/joomla/html/form.php', + '/libraries/joomla/html/grid.php', + '/libraries/joomla/html/html.php', + '/libraries/joomla/html/index.html', + '/libraries/joomla/html/jgrid.php', + '/libraries/joomla/html/list.php', + '/libraries/joomla/html/number.php', + '/libraries/joomla/html/rules.php', + '/libraries/joomla/html/select.php', + '/libraries/joomla/html/sliders.php', + '/libraries/joomla/html/string.php', + '/libraries/joomla/html/tabs.php', + '/libraries/joomla/html/tel.php', + '/libraries/joomla/html/user.php', + '/libraries/joomla/html/language/index.html', + '/libraries/joomla/html/language/en-GB/en-GB.jhtmldate.ini', + '/libraries/joomla/html/language/en-GB/index.html', + '/libraries/joomla/installer/adapters/component.php', + '/libraries/joomla/installer/adapters/file.php', + '/libraries/joomla/installer/adapters/index.html', + '/libraries/joomla/installer/adapters/language.php', + '/libraries/joomla/installer/adapters/library.php', + '/libraries/joomla/installer/adapters/module.php', + '/libraries/joomla/installer/adapters/package.php', + '/libraries/joomla/installer/adapters/plugin.php', + '/libraries/joomla/installer/adapters/template.php', + '/libraries/joomla/installer/extension.php', + '/libraries/joomla/installer/helper.php', + '/libraries/joomla/installer/index.html', + '/libraries/joomla/installer/librarymanifest.php', + '/libraries/joomla/installer/packagemanifest.php', + '/libraries/joomla/pagination/index.html', + '/libraries/joomla/pagination/object.php', + '/libraries/joomla/pagination/pagination.php', + '/libraries/legacy/html/contentlanguage.php', + '/libraries/legacy/html/index.html', + '/libraries/legacy/html/menu.php', + '/media/system/css/mooRainbow.css', + '/media/system/js/mooRainbow-uncompressed.js', + '/media/system/js/mooRainbow.js', + '/media/system/js/swf-uncompressed.js', + '/media/system/js/swf.js', + '/media/system/js/uploader-uncompressed.js', + '/media/system/js/uploader.js', + '/media/system/swf/index.html', + '/media/system/swf/uploader.swf', + // Joomla! 3.2 + '/administrator/components/com_contact/models/fields/modal/contacts.php', + '/administrator/components/com_newsfeeds/models/fields/modal/newsfeeds.php', + ); + + // TODO There is an issue while deleting folders using the ftp mode + $folders = array( + '/administrator/components/com_admin/sql/updates/sqlsrv', + '/media/com_finder/images/mime', + '/media/com_finder/images', + '/components/com_media/helpers', + // Joomla 3.0 + '/administrator/components/com_contact/elements', + '/administrator/components/com_content/elements', + '/administrator/components/com_installer/models/fields', + '/administrator/components/com_installer/models/forms', + '/administrator/components/com_modules/models/fields', + '/administrator/components/com_newsfeeds/elements', + '/administrator/components/com_templates/views/prevuuw/tmpl', + '/administrator/components/com_templates/views/prevuuw', + '/libraries/cms/controller', + '/libraries/cms/model', + '/libraries/cms/view', + '/libraries/joomla/application/cli', + '/libraries/joomla/application/component', + '/libraries/joomla/application/input', + '/libraries/joomla/application/module', + '/libraries/joomla/cache/storage/helpers', + '/libraries/joomla/database/table', + '/libraries/joomla/database/database', + '/libraries/joomla/error', + '/libraries/joomla/filesystem/archive', + '/libraries/joomla/html/html', + '/libraries/joomla/html/toolbar', + '/libraries/joomla/html/toolbar/button', + '/libraries/joomla/html/parameter', + '/libraries/joomla/html/parameter/element', + '/libraries/joomla/image/filters', + '/libraries/joomla/log/loggers', + // Joomla! 3.1 + '/libraries/joomla/form/rules', + '/libraries/joomla/html/language/en-GB', + '/libraries/joomla/html/language', + '/libraries/joomla/html', + '/libraries/joomla/installer/adapters', + '/libraries/joomla/installer', + '/libraries/joomla/pagination', + '/libraries/legacy/html', + '/media/system/swf/', + ); + + jimport('joomla.filesystem.file'); + foreach ($files as $file) + { + if (JFile::exists(JPATH_ROOT . $file) && !JFile::delete(JPATH_ROOT . $file)) + { + echo JText::sprintf('FILES_JOOMLA_ERROR_FILE_FOLDER', $file) . '
'; + } + } + + jimport('joomla.filesystem.folder'); + foreach ($folders as $folder) + { + if (JFolder::exists(JPATH_ROOT . $folder) && !JFolder::delete(JPATH_ROOT . $folder)) + { + echo JText::sprintf('FILES_JOOMLA_ERROR_FILE_FOLDER', $folder) . '
'; + } + } + } +} diff --git a/administrator/components/com_admin/sql/index.html b/administrator/components/com_admin/sql/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/sql/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/sql/updates/index.html b/administrator/components/com_admin/sql/updates/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/sql/updates/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-06.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-06.sql new file mode 100644 index 0000000..7ee6938 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-06.sql @@ -0,0 +1,9 @@ +INSERT INTO `#__extensions` (`extension_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `custom_data`, `system_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES +(437, 'plg_quickicon_joomlaupdate', 'plugin', 'joomlaupdate', 'quickicon', 0, 1, 1, 1, '', '{}', '', '', 0, '0000-00-00 00:00:00', 0, 0), +(438, 'plg_quickicon_extensionupdate', 'plugin', 'extensionupdate', 'quickicon', 0, 1, 1, 1, '', '{}', '', '', 0, '0000-00-00 00:00:00', 0, 0); + +ALTER TABLE `#__update_sites` ADD COLUMN `last_check_timestamp` bigint(20) DEFAULT '0' AFTER `enabled`; + +REPLACE INTO `#__update_sites` VALUES +(1, 'Joomla Core', 'collection', 'http://update.joomla.org/core/list.xml', 1, 0), +(2, 'Joomla Extension Directory', 'collection', 'http://update.joomla.org/jed/list.xml', 1, 0); diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-16.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-16.sql new file mode 100644 index 0000000..77ed80d --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-16.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS `#__overrider` ( + `id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key', + `constant` varchar(255) NOT NULL, + `string` text NOT NULL, + `file` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) DEFAULT CHARSET=utf8; \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-19.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-19.sql new file mode 100644 index 0000000..94e9c9a --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-19.sql @@ -0,0 +1,20 @@ +CREATE TABLE IF NOT EXISTS `#__user_notes` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `catid` int(10) unsigned NOT NULL DEFAULT '0', + `subject` varchar(100) NOT NULL DEFAULT '', + `body` text NOT NULL, + `state` tinyint(3) NOT NULL DEFAULT '0', + `checked_out` int(10) unsigned NOT NULL DEFAULT '0', + `checked_out_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `created_user_id` int(10) unsigned NOT NULL DEFAULT '0', + `created_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `modified_user_id` int(10) unsigned NOT NULL, + `modified_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `review_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `publish_up` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `publish_down` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_category_id` (`catid`) +) DEFAULT CHARSET=utf8; diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-20.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-20.sql new file mode 100644 index 0000000..1de207e --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-20.sql @@ -0,0 +1,7 @@ +SELECT @old_params:= CONCAT(SUBSTRING_INDEX(SUBSTRING(params, LOCATE('"filters":', params)), '}}', 1), '}}') as filters +FROM `#__extensions` +WHERE name="com_content"; + +UPDATE `#__extensions` +SET params=CONCAT('{',SUBSTRING(params, 2, CHAR_LENGTH(params)-2),IF(params='','',','),@old_params,'}') +WHERE name="com_config"; \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-21-1.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-21-1.sql new file mode 100644 index 0000000..481ed6c --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-21-1.sql @@ -0,0 +1,11 @@ +INSERT INTO `#__extensions` (`extension_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `custom_data`, `system_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES +(27, 'com_finder', 'component', 'com_finder', '', 1, 1, 0, 0, '', '{"show_description":"1","description_length":255,"allow_empty_query":"0","show_url":"1","show_advanced":"1","expand_advanced":"0","show_date_filters":"0","highlight_terms":"1","opensearch_name":"","opensearch_description":"","batch_size":"50","memory_table_limit":30000,"title_multiplier":"1.7","text_multiplier":"0.7","meta_multiplier":"1.2","path_multiplier":"2.0","misc_multiplier":"0.3","stemmer":"porter_en"}', '', '', 0, '0000-00-00 00:00:00', 0, 0), +(439, 'plg_captcha_recaptcha', 'plugin', 'recaptcha', 'captcha', 0, 1, 1, 0, '{}', '{"public_key":"","private_key":"","theme":"clean"}', '', '', 0, '0000-00-00 00:00:00', 0, 0), +(440, 'plg_system_highlight', 'plugin', 'highlight', 'system', 0, 1, 1, 0, '', '{}', '', '', 0, '0000-00-00 00:00:00', 7, 0), +(441, 'plg_content_finder', 'plugin', 'finder', 'content', 0, 0, 1, 0, '{"legacy":false,"name":"plg_content_finder","type":"plugin","creationDate":"December 2011","author":"Joomla! Project","copyright":"Copyright (C) 2005 - 2012 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"1.7.0","description":"PLG_CONTENT_FINDER_XML_DESCRIPTION","group":""}', '{}', '', '', 0, '0000-00-00 00:00:00', 0, 0), +(442, 'plg_finder_categories', 'plugin', 'categories', 'finder', 0, 1, 1, 0, '', '{}', '', '', 0, '0000-00-00 00:00:00', 1, 0), +(443, 'plg_finder_contacts', 'plugin', 'contacts', 'finder', 0, 1, 1, 0, '', '{}', '', '', 0, '0000-00-00 00:00:00', 2, 0), +(444, 'plg_finder_content', 'plugin', 'content', 'finder', 0, 1, 1, 0, '', '{}', '', '', 0, '0000-00-00 00:00:00', 3, 0), +(445, 'plg_finder_newsfeeds', 'plugin', 'newsfeeds', 'finder', 0, 1, 1, 0, '', '{}', '', '', 0, '0000-00-00 00:00:00', 4, 0), +(446, 'plg_finder_weblinks', 'plugin', 'weblinks', 'finder', 0, 1, 1, 0, '', '{}', '', '', 0, '0000-00-00 00:00:00', 5, 0), +(223, 'mod_finder', 'module', 'mod_finder', '', 0, 1, 0, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0); diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-21-2.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-21-2.sql new file mode 100644 index 0000000..dd1a0d4 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-21-2.sql @@ -0,0 +1,244 @@ +CREATE TABLE IF NOT EXISTS `#__finder_links_terms0` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms1` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms2` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms3` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms4` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms5` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms6` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms7` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms8` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms9` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_links_termsa` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_links_termsb` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_links_termsc` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_links_termsd` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_links_termse` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_links_termsf` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_taxonomy` ( + `id` int(10) unsigned NOT NULL auto_increment, + `parent_id` int(10) unsigned NOT NULL default '0', + `title` varchar(255) NOT NULL, + `state` tinyint(1) unsigned NOT NULL default '1', + `access` tinyint(1) unsigned NOT NULL default '0', + `ordering` tinyint(1) unsigned NOT NULL default '0', + PRIMARY KEY (`id`), + KEY `parent_id` (`parent_id`), + KEY `state` (`state`), + KEY `ordering` (`ordering`), + KEY `access` (`access`), + KEY `idx_parent_published` (`parent_id`,`state`,`access`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_taxonomy_map` ( + `link_id` int(10) unsigned NOT NULL, + `node_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`link_id`,`node_id`), + KEY `link_id` (`link_id`), + KEY `node_id` (`node_id`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_terms` ( + `term_id` int(10) unsigned NOT NULL auto_increment, + `term` varchar(75) NOT NULL, + `stem` varchar(75) NOT NULL, + `common` tinyint(1) unsigned NOT NULL default '0', + `phrase` tinyint(1) unsigned NOT NULL default '0', + `weight` float unsigned NOT NULL default '0', + `soundex` varchar(75) NOT NULL, + `links` int(10) NOT NULL default '0', + PRIMARY KEY (`term_id`), + UNIQUE KEY `idx_term` (`term`), + KEY `idx_term_phrase` (`term`,`phrase`), + KEY `idx_stem_phrase` (`stem`,`phrase`), + KEY `idx_soundex_phrase` (`soundex`,`phrase`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_terms_common` ( + `term` varchar(75) NOT NULL, + `language` varchar(3) NOT NULL, + KEY `idx_word_lang` (`term`,`language`), + KEY `idx_lang` (`language`) +) DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_tokens` ( + `term` varchar(75) NOT NULL, + `stem` varchar(75) NOT NULL, + `common` tinyint(1) unsigned NOT NULL default '0', + `phrase` tinyint(1) unsigned NOT NULL default '0', + `weight` float unsigned NOT NULL default '1', + `context` tinyint(1) unsigned NOT NULL default '2', + KEY `idx_word` (`term`), + KEY `idx_context` (`context`) +) ENGINE=MEMORY DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_tokens_aggregate` ( + `term_id` int(10) unsigned NOT NULL, + `map_suffix` char(1) NOT NULL, + `term` varchar(75) NOT NULL, + `stem` varchar(75) NOT NULL, + `common` tinyint(1) unsigned NOT NULL default '0', + `phrase` tinyint(1) unsigned NOT NULL default '0', + `term_weight` float unsigned NOT NULL, + `context` tinyint(1) unsigned NOT NULL default '2', + `context_weight` float unsigned NOT NULL, + `total_weight` float unsigned NOT NULL, + KEY `token` (`term`), + KEY `keyword_id` (`term_id`) +) ENGINE=MEMORY DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__finder_types` ( + `id` int(10) unsigned NOT NULL auto_increment, + `title` varchar(100) NOT NULL, + `mime` varchar(100) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `title` (`title`) +) DEFAULT CHARSET=utf8; + + diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-22.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-22.sql new file mode 100644 index 0000000..fe86a15 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-22.sql @@ -0,0 +1,123 @@ +REPLACE INTO `#__finder_taxonomy` (`id`, `parent_id`, `title`, `state`, `access`, `ordering`) VALUES +(1, 0, 'ROOT', 0, 0, 0); + +REPLACE INTO `#__finder_terms_common` (`term`, `language`) VALUES +('a', 'en'), +('about', 'en'), +('after', 'en'), +('ago', 'en'), +('all', 'en'), +('am', 'en'), +('an', 'en'), +('and', 'en'), +('ani', 'en'), +('any', 'en'), +('are', 'en'), +('aren''t', 'en'), +('as', 'en'), +('at', 'en'), +('be', 'en'), +('but', 'en'), +('by', 'en'), +('for', 'en'), +('from', 'en'), +('get', 'en'), +('go', 'en'), +('how', 'en'), +('if', 'en'), +('in', 'en'), +('into', 'en'), +('is', 'en'), +('isn''t', 'en'), +('it', 'en'), +('its', 'en'), +('me', 'en'), +('more', 'en'), +('most', 'en'), +('must', 'en'), +('my', 'en'), +('new', 'en'), +('no', 'en'), +('none', 'en'), +('not', 'en'), +('noth', 'en'), +('nothing', 'en'), +('of', 'en'), +('off', 'en'), +('often', 'en'), +('old', 'en'), +('on', 'en'), +('onc', 'en'), +('once', 'en'), +('onli', 'en'), +('only', 'en'), +('or', 'en'), +('other', 'en'), +('our', 'en'), +('ours', 'en'), +('out', 'en'), +('over', 'en'), +('page', 'en'), +('she', 'en'), +('should', 'en'), +('small', 'en'), +('so', 'en'), +('some', 'en'), +('than', 'en'), +('thank', 'en'), +('that', 'en'), +('the', 'en'), +('their', 'en'), +('theirs', 'en'), +('them', 'en'), +('then', 'en'), +('there', 'en'), +('these', 'en'), +('they', 'en'), +('this', 'en'), +('those', 'en'), +('thus', 'en'), +('time', 'en'), +('times', 'en'), +('to', 'en'), +('too', 'en'), +('true', 'en'), +('under', 'en'), +('until', 'en'), +('up', 'en'), +('upon', 'en'), +('use', 'en'), +('user', 'en'), +('users', 'en'), +('veri', 'en'), +('version', 'en'), +('very', 'en'), +('via', 'en'), +('want', 'en'), +('was', 'en'), +('way', 'en'), +('were', 'en'), +('what', 'en'), +('when', 'en'), +('where', 'en'), +('whi', 'en'), +('which', 'en'), +('who', 'en'), +('whom', 'en'), +('whose', 'en'), +('why', 'en'), +('wide', 'en'), +('will', 'en'), +('with', 'en'), +('within', 'en'), +('without', 'en'), +('would', 'en'), +('yes', 'en'), +('yet', 'en'), +('you', 'en'), +('your', 'en'), +('yours', 'en'); + + +INSERT INTO `#__menu` (`id`, `menutype`, `title`, `alias`, `note`, `path`, `link`, `type`, `published`, `parent_id`, `level`, `component_id`, `ordering`, `checked_out`, `checked_out_time`, `browserNav`, `access`, `img`, `template_style_id`, `params`, `lft`, `rgt`, `home`, `language`, `client_id`) VALUES +(21, 'menu', 'com_finder', 'Smart Search', '', 'Smart Search', 'index.php?option=com_finder', 'component', 0, 1, 1, 27, 0, 0, '0000-00-00 00:00:00', 0, 0, 'class:finder', 0, '', 41, 42, 0, '*', 1); diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-23.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-23.sql new file mode 100644 index 0000000..5dae6e5 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-23.sql @@ -0,0 +1,47 @@ +CREATE TABLE IF NOT EXISTS `#__finder_filters` ( + `filter_id` int(10) unsigned NOT NULL auto_increment, + `title` varchar(255) NOT NULL, + `alias` varchar(255) NOT NULL, + `state` tinyint(1) NOT NULL default '1', + `created` datetime NOT NULL default '0000-00-00 00:00:00', + `created_by` int(10) unsigned NOT NULL, + `created_by_alias` varchar(255) NOT NULL, + `modified` datetime NOT NULL default '0000-00-00 00:00:00', + `modified_by` int(10) unsigned NOT NULL default '0', + `checked_out` int(10) unsigned NOT NULL default '0', + `checked_out_time` datetime NOT NULL default '0000-00-00 00:00:00', + `map_count` int(10) unsigned NOT NULL default '0', + `data` text NOT NULL, + `params` mediumtext, + PRIMARY KEY (`filter_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__finder_links` ( + `link_id` int(10) unsigned NOT NULL auto_increment, + `url` varchar(255) NOT NULL, + `route` varchar(255) NOT NULL, + `title` varchar(255) default NULL, + `description` varchar(255) default NULL, + `indexdate` datetime NOT NULL default '0000-00-00 00:00:00', + `md5sum` varchar(32) default NULL, + `published` tinyint(1) NOT NULL default '1', + `state` int(5) default '1', + `access` int(5) default '0', + `language` varchar(8) NOT NULL, + `publish_start_date` datetime NOT NULL default '0000-00-00 00:00:00', + `publish_end_date` datetime NOT NULL default '0000-00-00 00:00:00', + `start_date` datetime NOT NULL default '0000-00-00 00:00:00', + `end_date` datetime NOT NULL default '0000-00-00 00:00:00', + `list_price` double unsigned NOT NULL default '0', + `sale_price` double unsigned NOT NULL default '0', + `type_id` int(11) NOT NULL, + `object` mediumblob NOT NULL, + PRIMARY KEY (`link_id`), + KEY `idx_type` (`type_id`), + KEY `idx_title` (`title`), + KEY `idx_md5` (`md5sum`), + KEY `idx_url` (`url`(75)), + KEY `idx_published_list` (`published`,`state`,`access`,`publish_start_date`,`publish_end_date`,`list_price`), + KEY `idx_published_sale` (`published`,`state`,`access`,`publish_start_date`,`publish_end_date`,`sale_price`) +) DEFAULT CHARSET=utf8; + diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-24.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-24.sql new file mode 100644 index 0000000..8f7014c --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2011-12-24.sql @@ -0,0 +1,3 @@ +ALTER TABLE `#__menu` DROP INDEX `idx_client_id_parent_id_alias`; + +ALTER TABLE `#__menu` ADD UNIQUE `idx_client_id_parent_id_alias_language` ( `client_id` , `parent_id` , `alias` , `language` ); \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.0-2012-01-10.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2012-01-10.sql new file mode 100644 index 0000000..c912214 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2012-01-10.sql @@ -0,0 +1 @@ +ALTER TABLE `#__updates` ADD COLUMN `infourl` text NOT NULL AFTER `detailsurl`; diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.0-2012-01-14.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2012-01-14.sql new file mode 100644 index 0000000..4817357 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.0-2012-01-14.sql @@ -0,0 +1,2 @@ +ALTER TABLE `#__languages` CHANGE `sitename` `sitename` VARCHAR( 1024 ) NOT NULL DEFAULT ''; + diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.1-2012-01-26.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.1-2012-01-26.sql new file mode 100644 index 0000000..65aad5b --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.1-2012-01-26.sql @@ -0,0 +1,8 @@ +INSERT INTO `#__extensions` (`extension_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `custom_data`, `system_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES +(314, 'mod_version', 'module', 'mod_version', '', 1, 1, 1, 0, '{"legacy":false,"name":"mod_version","type":"module","creationDate":"January 2012","author":"Joomla! Project","copyright":"Copyright (C) 2005 - 2012 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"2.5.0","description":"MOD_VERSION_XML_DESCRIPTION","group":""}', '{"format":"short","product":"1","cache":"0"}', '', '', 0, '0000-00-00 00:00:00', 0, 0); + +INSERT INTO `#__modules` (`title`, `note`, `content`, `ordering`, `position`, `checked_out`, `checked_out_time`, `publish_up`, `publish_down`, `published`, `module`, `access`, `showtitle`, `params`, `client_id`, `language`) VALUES +('Joomla Version', '', '', 1, 'footer', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_version', 3, 1, '{"format":"short","product":"1","layout":"_:default","moduleclass_sfx":"","cache":"0"}', 1, '*'); + +INSERT INTO `#__modules_menu` (`moduleid`, `menuid`) VALUES +(LAST_INSERT_ID(), 0); \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.2-2012-03-05.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.2-2012-03-05.sql new file mode 100644 index 0000000..1c06a39 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.2-2012-03-05.sql @@ -0,0 +1 @@ +# Dummy SQL file to set schema version \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.3-2012-03-13.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.3-2012-03-13.sql new file mode 100644 index 0000000..1c06a39 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.3-2012-03-13.sql @@ -0,0 +1 @@ +# Dummy SQL file to set schema version \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.4-2012-03-18.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.4-2012-03-18.sql new file mode 100644 index 0000000..16f9f86 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.4-2012-03-18.sql @@ -0,0 +1,5 @@ +INSERT INTO `#__extensions` (`extension_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `custom_data`, `system_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES +(28, 'com_joomlaupdate', 'component', 'com_joomlaupdate', '', 1, 1, 0, 1, '{"legacy":false,"name":"com_joomlaupdate","type":"component","creationDate":"February 2012","author":"Joomla! Project","copyright":"(C) 2005 - 2012 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"2.5.2","description":"COM_JOOMLAUPDATE_XML_DESCRIPTION","group":""}', '{}', '', '', 0, '0000-00-00 00:00:00', 0, 0); + +INSERT INTO `#__menu` (`id`, `menutype`, `title`, `alias`, `note`, `path`, `link`, `type`, `published`, `parent_id`, `level`, `component_id`, `ordering`, `checked_out`, `checked_out_time`, `browserNav`, `access`, `img`, `template_style_id`, `params`, `lft`, `rgt`, `home`, `language`, `client_id`) VALUES +(22, 'menu', 'com_joomlaupdate', 'Joomla! Update', '', 'Joomla! Update', 'index.php?option=com_joomlaupdate', 'component', 0, 1, 1, 28, 0, 0, '0000-00-00 00:00:00', 0, 0, 'class:joomlaupdate', 0, '', 41, 42, 0, '*', 1); diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.4-2012-03-19.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.4-2012-03-19.sql new file mode 100644 index 0000000..9153568 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.4-2012-03-19.sql @@ -0,0 +1,7 @@ +ALTER TABLE `#__languages` ADD COLUMN `access` integer unsigned NOT NULL default 0 AFTER `published`; + +ALTER TABLE `#__languages` ADD KEY `idx_access` (`access`); + +UPDATE `#__categories` SET `extension` = 'com_users.notes' WHERE `extension` = 'com_users'; + +UPDATE `#__extensions` SET `enabled` = '1' WHERE `protected` = '1' AND `type` <> 'plugin'; diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.5.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.5.sql new file mode 100644 index 0000000..c73b708 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.5.sql @@ -0,0 +1,3 @@ +ALTER TABLE `#__redirect_links` ADD COLUMN `hits` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `comment`; +ALTER TABLE `#__users` ADD COLUMN `lastResetTime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Date of last password reset'; +ALTER TABLE `#__users` ADD COLUMN `resetCount` int(11) NOT NULL DEFAULT '0' COMMENT 'Count of password resets since lastResetTime'; \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.6.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.6.sql new file mode 100644 index 0000000..ff1afae --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.6.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 2.5.6 \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/mysql/2.5.7.sql b/administrator/components/com_admin/sql/updates/mysql/2.5.7.sql new file mode 100644 index 0000000..3209797 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/2.5.7.sql @@ -0,0 +1 @@ +INSERT INTO `#__update_sites` (`name`, `type`, `location`, `enabled`, `last_check_timestamp`) VALUES('Accredited Joomla! Translations','collection','http://update.joomla.org/language/translationlist.xml',1,0);INSERT INTO `#__update_sites_extensions` (`update_site_id`, `extension_id`) VALUES(LAST_INSERT_ID(),600);UPDATE `#__assets` SET name=REPLACE( name, 'com_user.notes.category','com_users.category' );UPDATE `#__categories` SET extension=REPLACE( extension, 'com_user.notes.category','com_users.category' ); \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/mysql/3.0.0.sql b/administrator/components/com_admin/sql/updates/mysql/3.0.0.sql new file mode 100644 index 0000000..35cd42e --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/3.0.0.sql @@ -0,0 +1,154 @@ +ALTER TABLE `#__users` DROP KEY `usertype`; +ALTER TABLE `#__session` DROP KEY `whosonline`; + +DROP TABLE IF EXISTS `#__update_categories`; + +ALTER TABLE `#__contact_details` DROP `imagepos`; +ALTER TABLE `#__content` DROP COLUMN `title_alias`; +ALTER TABLE `#__content` DROP COLUMN `sectionid`; +ALTER TABLE `#__content` DROP COLUMN `mask`; +ALTER TABLE `#__content` DROP COLUMN `parentid`; +ALTER TABLE `#__newsfeeds` DROP COLUMN `filename`; +ALTER TABLE `#__weblinks` DROP COLUMN `sid`; +ALTER TABLE `#__weblinks` DROP COLUMN `date`; +ALTER TABLE `#__weblinks` DROP COLUMN `archived`; +ALTER TABLE `#__weblinks` DROP COLUMN `approved`; +ALTER TABLE `#__menu` DROP COLUMN `ordering`; +ALTER TABLE `#__session` DROP COLUMN `usertype`; +ALTER TABLE `#__users` DROP COLUMN `usertype`; +ALTER TABLE `#__updates` DROP COLUMN `categoryid`; + +UPDATE `#__extensions` SET protected = 0 WHERE +`name` = 'com_search' OR +`name` = 'mod_articles_archive' OR +`name` = 'mod_articles_latest' OR +`name` = 'mod_banners' OR +`name` = 'mod_feed' OR +`name` = 'mod_footer' OR +`name` = 'mod_users_latest' OR +`name` = 'mod_articles_category' OR +`name` = 'mod_articles_categories' OR +`name` = 'plg_content_pagebreak' OR +`name` = 'plg_content_pagenavigation' OR +`name` = 'plg_content_vote' OR +`name` = 'plg_editors_tinymce' OR +`name` = 'plg_system_p3p' OR +`name` = 'plg_user_contactcreator' OR +`name` = 'plg_user_profile'; + +DELETE FROM `#__extensions` WHERE `extension_id` = 800; + +ALTER TABLE `#__assets` ENGINE=InnoDB; +ALTER TABLE `#__associations` ENGINE=InnoDB; +ALTER TABLE `#__banners` ENGINE=InnoDB; +ALTER TABLE `#__banner_clients` ENGINE=InnoDB; +ALTER TABLE `#__banner_tracks` ENGINE=InnoDB; +ALTER TABLE `#__categories` ENGINE=InnoDB; +ALTER TABLE `#__contact_details` ENGINE=InnoDB; +ALTER TABLE `#__content` ENGINE=InnoDB; +ALTER TABLE `#__content_frontpage` ENGINE=InnoDB; +ALTER TABLE `#__content_rating` ENGINE=InnoDB; +ALTER TABLE `#__core_log_searches` ENGINE=InnoDB; +ALTER TABLE `#__extensions` ENGINE=InnoDB; +ALTER TABLE `#__finder_filters` ENGINE=InnoDB; +ALTER TABLE `#__finder_links` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_terms0` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_terms1` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_terms2` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_terms3` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_terms4` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_terms5` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_terms6` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_terms7` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_terms8` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_terms9` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_termsa` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_termsb` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_termsc` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_termsd` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_termse` ENGINE=InnoDB; +ALTER TABLE `#__finder_links_termsf` ENGINE=InnoDB; +ALTER TABLE `#__finder_taxonomy` ENGINE=InnoDB; +ALTER TABLE `#__finder_taxonomy_map` ENGINE=InnoDB; +ALTER TABLE `#__finder_terms` ENGINE=InnoDB; +ALTER TABLE `#__finder_terms_common` ENGINE=InnoDB; +ALTER TABLE `#__finder_types` ENGINE=InnoDB; +ALTER TABLE `#__languages` ENGINE=InnoDB; +ALTER TABLE `#__menu` ENGINE=InnoDB; +ALTER TABLE `#__menu_types` ENGINE=InnoDB; +ALTER TABLE `#__messages` ENGINE=InnoDB; +ALTER TABLE `#__messages_cfg` ENGINE=InnoDB; +ALTER TABLE `#__modules` ENGINE=InnoDB; +ALTER TABLE `#__modules_menu` ENGINE=InnoDB; +ALTER TABLE `#__newsfeeds` ENGINE=InnoDB; +ALTER TABLE `#__overrider` ENGINE=InnoDB; +ALTER TABLE `#__redirect_links` ENGINE=InnoDB; +ALTER TABLE `#__schemas` ENGINE=InnoDB; +ALTER TABLE `#__session` ENGINE=InnoDB; +ALTER TABLE `#__template_styles` ENGINE=InnoDB; +ALTER TABLE `#__updates` ENGINE=InnoDB; +ALTER TABLE `#__update_sites` ENGINE=InnoDB; +ALTER TABLE `#__update_sites_extensions` ENGINE=InnoDB; +ALTER TABLE `#__users` ENGINE=InnoDB; +ALTER TABLE `#__usergroups` ENGINE=InnoDB; +ALTER TABLE `#__user_notes` ENGINE=InnoDB; +ALTER TABLE `#__user_profiles` ENGINE=InnoDB; +ALTER TABLE `#__user_usergroup_map` ENGINE=InnoDB; +ALTER TABLE `#__viewlevels` ENGINE=InnoDB; +ALTER TABLE `#__weblinks` ENGINE=InnoDB; + +ALTER TABLE `#__weblinks` ADD COLUMN `version` int(10) unsigned NOT NULL DEFAULT '1'; +ALTER TABLE `#__weblinks` ADD COLUMN `images` text NOT NULL; +ALTER TABLE `#__newsfeeds` ADD COLUMN `description` text NOT NULL; +ALTER TABLE `#__newsfeeds` ADD COLUMN `version` int(10) unsigned NOT NULL DEFAULT '1'; +ALTER TABLE `#__newsfeeds` ADD COLUMN `hits` int(10) unsigned NOT NULL DEFAULT '0'; +ALTER TABLE `#__newsfeeds` ADD COLUMN `images` text NOT NULL; +ALTER TABLE `#__contact_details` ADD COLUMN `version` int(10) unsigned NOT NULL DEFAULT '1'; +ALTER TABLE `#__contact_details` ADD COLUMN `hits` int(10) unsigned NOT NULL DEFAULT '0'; +ALTER TABLE `#__banners` ADD COLUMN `created_by` int(10) unsigned NOT NULL DEFAULT '0'; +ALTER TABLE `#__banners` ADD COLUMN `created_by_alias` varchar(255) NOT NULL DEFAULT ''; +ALTER TABLE `#__banners` ADD COLUMN `modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00'; +ALTER TABLE `#__banners` ADD COLUMN `modified_by` int(10) unsigned NOT NULL DEFAULT '0'; +ALTER TABLE `#__banners` ADD COLUMN `version` int(10) unsigned NOT NULL DEFAULT '1'; +ALTER TABLE `#__categories` ADD COLUMN `version` int(10) unsigned NOT NULL DEFAULT '1'; +UPDATE `#__assets` SET name=REPLACE( name, 'com_user.notes.category','com_users.category' ); +UPDATE `#__categories` SET extension=REPLACE( extension, 'com_user.notes.category','com_users.category' ); + +ALTER TABLE `#__finder_terms` ADD COLUMN `language` char(3) NOT NULL DEFAULT ''; +ALTER TABLE `#__finder_tokens` ADD COLUMN `language` char(3) NOT NULL DEFAULT ''; +ALTER TABLE `#__finder_tokens_aggregate` ADD COLUMN `language` char(3) NOT NULL DEFAULT ''; + +INSERT INTO `#__extensions` + (`name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `custom_data`, `system_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) + VALUES + ('isis', 'template', 'isis', '', 1, 1, 1, 0, '{"name":"isis","type":"template","creationDate":"3\\/30\\/2012","author":"Kyle Ledbetter","copyright":"Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"","version":"1.0","description":"TPL_ISIS_XML_DESCRIPTION","group":""}', '{"templateColor":"","logoFile":""}', '', '', 0, '0000-00-00 00:00:00', 0, 0), + ('protostar', 'template', 'protostar', '', 0, 1, 1, 0, '{"name":"protostar","type":"template","creationDate":"4\\/30\\/2012","author":"Kyle Ledbetter","copyright":"Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"","version":"1.0","description":"TPL_PROTOSTAR_XML_DESCRIPTION","group":""}', '{"templateColor":"","logoFile":"","googleFont":"1","googleFontName":"Open+Sans","fluidContainer":"0"}', '', '', 0, '0000-00-00 00:00:00', 0, 0), + ('beez3', 'template', 'beez3', '', 0, 1, 1, 0, '{"legacy":false,"name":"beez3","type":"template","creationDate":"25 November 2009","author":"Angie Radtke","copyright":"Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.","authorEmail":"a.radtke@derauftritt.de","authorUrl":"http:\\/\\/www.der-auftritt.de","version":"1.6.0","description":"TPL_BEEZ3_XML_DESCRIPTION","group":""}', '{"wrapperSmall":"53","wrapperLarge":"72","sitetitle":"","sitedescription":"","navposition":"center","templatecolor":"nature"}', '', '', 0, '0000-00-00 00:00:00', 0, 0); + +INSERT INTO `#__template_styles` (`template`, `client_id`, `home`, `title`, `params`) VALUES + ('protostar', 0, '0', 'protostar - Default', '{"templateColor":"","logoFile":"","googleFont":"1","googleFontName":"Open+Sans","fluidContainer":"0"}'), + ('isis', 1, '1', 'isis - Default', '{"templateColor":"","logoFile":""}'), + ('beez3', 0, '0', 'beez3 - Default', '{"wrapperSmall":53,"wrapperLarge":72,"logo":"","sitetitle":"","sitedescription":"","navposition":"center","bootstrap":"","templatecolor":"nature","headerImage":"","backgroundcolor":"#eee"}'); + +UPDATE `#__template_styles` +SET home = (CASE WHEN (SELECT count FROM (SELECT count(`id`) AS count + FROM `#__template_styles` + WHERE home = '1' + AND client_id = 1) as c) = 0 + THEN '1' + ELSE '0' + END) +WHERE template = 'isis' +AND home != '1'; + +UPDATE `#__template_styles` +SET home = 0 +WHERE template = 'bluestork'; + +INSERT INTO `#__extensions` (`extension_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `custom_data`, `system_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES +(315, 'mod_stats_admin', 'module', 'mod_stats_admin', '', 1, 1, 1, 0, '{"name":"mod_stats_admin","type":"module","creationDate":"September 2012","author":"Joomla! Project","copyright":"Copyright (C) 2005 - 2012 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"3.0.0","description":"MOD_STATS_XML_DESCRIPTION","group":""}', '{"serverinfo":"0","siteinfo":"0","counter":"0","increase":"0","cache":"1","cache_time":"900","cachemode":"static"}', '', '', 0, '0000-00-00 00:00:00', 0, 0); + +UPDATE `#__update_sites` +SET location = 'http://update.joomla.org/language/translationlist_3.xml' +WHERE location = 'http://update.joomla.org/language/translationlist.xml' +AND name = 'Accredited Joomla! Translations'; diff --git a/administrator/components/com_admin/sql/updates/mysql/3.0.1.sql b/administrator/components/com_admin/sql/updates/mysql/3.0.1.sql new file mode 100644 index 0000000..c9f8fda --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/3.0.1.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.0.1 \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/mysql/3.0.2.sql b/administrator/components/com_admin/sql/updates/mysql/3.0.2.sql new file mode 100644 index 0000000..df708fc --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/3.0.2.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.0.2 \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/mysql/3.0.3.sql b/administrator/components/com_admin/sql/updates/mysql/3.0.3.sql new file mode 100644 index 0000000..23fcc72 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/3.0.3.sql @@ -0,0 +1 @@ +ALTER TABLE `#__associations` CHANGE `id` `id` INT(11) NOT NULL COMMENT 'A reference to the associated item.'; \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/mysql/3.1.0.sql b/administrator/components/com_admin/sql/updates/mysql/3.1.0.sql new file mode 100644 index 0000000..5b5cddb --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/3.1.0.sql @@ -0,0 +1,167 @@ +-- +-- Table structure for table `#__content_types` +-- + +CREATE TABLE IF NOT EXISTS `#__content_types` ( + `type_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `type_title` varchar(255) NOT NULL DEFAULT '', + `type_alias` varchar(255) NOT NULL DEFAULT '', + `table` varchar(255) NOT NULL DEFAULT '', + `rules` text NOT NULL, + `field_mappings` text NOT NULL, + `router` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`type_id`), + KEY `idx_alias` (`type_alias`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=10000; + +-- +-- Dumping data for table `#__content_types` +-- + +INSERT INTO `#__content_types` (`type_id`, `type_title`, `type_alias`, `table`, `rules`, `field_mappings`,`router`) VALUES +(1, 'Article', 'com_content.article', '{"special":{"dbtable":"#__content","key":"id","type":"Content","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"introtext", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"attribs", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"asset_id"}], "special": [{"fulltext":"fulltext"}]}','ContentHelperRoute::getArticleRoute'), +(2, 'Weblink', 'com_weblinks.weblink', '{"special":{"dbtable":"#__weblinks","key":"id","type":"Weblink","prefix":"WeblinksTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"description", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}], "special": []}','WeblinksHelperRoute::getWeblinkRoute'), +(3, 'Contact', 'com_contact.contact', '{"special":{"dbtable":"#__contact_details","key":"id","type":"Contact","prefix":"ContactTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"name","core_state":"published","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"address", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"image", "core_urls":"webpage", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}], "special": [{"con_position":"con_position","suburb":"suburb","state":"state","country":"country","postcode":"postcode","telephone":"telephone","fax":"fax","misc":"misc","email_to":"email_to","default_con":"default_con","user_id":"user_id","mobile":"mobile","sortname1":"sortname1","sortname2":"sortname2","sortname3":"sortname3"}]}','ContactHelperRoute::getContactRoute'), +(4, 'Newsfeed', 'com_newsfeeds.newsfeed', '{"special":{"dbtable":"#__newsfeeds","key":"id","type":"Newsfeed","prefix":"NewsfeedsTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"name","core_state":"published","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"description", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"link", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}], "special": [{"numarticles":"numarticles","cache_time":"cache_time","rtl":"rtl"}]}','NewsfeedsHelperRoute::getNewsfeedRoute'), +(5, 'User', 'com_users.user', '{"special":{"dbtable":"#__users","key":"id","type":"User","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"name","core_state":"null","core_alias":"username","core_created_time":"registerdate","core_modified_time":"lastvisitDate","core_body":"null", "core_hits":"null","core_publish_up":"null","core_publish_down":"null","access":"null", "core_params":"params", "core_featured":"null", "core_metadata":"null", "core_language":"null", "core_images":"null", "core_urls":"null", "core_version":"null", "core_ordering":"null", "core_metakey":"null", "core_metadesc":"null", "core_catid":"null", "core_xreference":"null", "asset_id":"null"}], "special": [{}]}','UsersHelperRoute::getUserRoute'), +(6, 'Article Category', 'com_content.category', '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}]}','ContentHelperRoute::getCategoryRoute'), +(7, 'Contact Category', 'com_contact.category', '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}]}','ContactHelperRoute::getCategoryRoute'), +(8, 'Newsfeeds Category', 'com_newsfeeds.category', '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}]}','NewsfeedsHelperRoute::getCategoryRoute'), +(9, 'Weblinks Category', 'com_weblinks.category', '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}]}','WeblinksHelperRoute::getCategoryRoute'), +(10, 'Tag', 'com_tags.tag', '{"special":{"dbtable":"#__tags","key":"tag_id","type":"Tag","prefix":"TagsTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"null", "core_xreference":"null", "asset_id":"null"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path"}]}','TagsHelperRoute::getTagRoute'); + +CREATE TABLE IF NOT EXISTS `#__contentitem_tag_map` ( + `type_alias` varchar(255) NOT NULL DEFAULT '', + `core_content_id` int(10) unsigned NOT NULL COMMENT 'PK from the core content table', + `content_item_id` int(11) NOT NULL COMMENT 'PK from the content type table', + `tag_id` int(10) unsigned NOT NULL COMMENT 'PK from the tag table', + `tag_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Date of most recent save for this tag-item', + `type_id` mediumint(8) NOT NULL COMMENT 'PK from the content_type table', + UNIQUE KEY `uc_ItemnameTagid` (`type_id`,`content_item_id`,`tag_id`), + KEY `idx_tag_type` (`tag_id`,`type_id`), + KEY `idx_date_id` (`tag_date`,`tag_id`), + KEY `idx_tag` (`tag_id`), + KEY `idx_type` (`type_id`), + KEY `idx_core_content_id` (`core_content_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Maps items from content tables to tags'; + +CREATE TABLE IF NOT EXISTS `#__tags` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `parent_id` int(10) unsigned NOT NULL DEFAULT '0', + `lft` int(11) NOT NULL DEFAULT '0', + `rgt` int(11) NOT NULL DEFAULT '0', + `level` int(10) unsigned NOT NULL DEFAULT '0', + `path` varchar(255) NOT NULL DEFAULT '', + `title` varchar(255) NOT NULL, + `alias` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', + `note` varchar(255) NOT NULL DEFAULT '', + `description` mediumtext NOT NULL, + `published` tinyint(1) NOT NULL DEFAULT '0', + `checked_out` int(11) unsigned NOT NULL DEFAULT '0', + `checked_out_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `access` int(10) unsigned NOT NULL DEFAULT '0', + `params` text NOT NULL, + `metadesc` varchar(1024) NOT NULL COMMENT 'The meta description for the page.', + `metakey` varchar(1024) NOT NULL COMMENT 'The meta keywords for the page.', + `metadata` varchar(2048) NOT NULL COMMENT 'JSON encoded metadata properties.', + `created_user_id` int(10) unsigned NOT NULL DEFAULT '0', + `created_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `created_by_alias` varchar(255) NOT NULL DEFAULT '', + `modified_user_id` int(10) unsigned NOT NULL DEFAULT '0', + `modified_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `images` text NOT NULL, + `urls` text NOT NULL, + `hits` int(10) unsigned NOT NULL DEFAULT '0', + `language` char(7) NOT NULL, + `version` int(10) unsigned NOT NULL DEFAULT '1', + `publish_up` datetime NOT NULL default '0000-00-00 00:00:00', + `publish_down` datetime NOT NULL default '0000-00-00 00:00:00', + PRIMARY KEY (`id`), + KEY `tag_idx` (`published`,`access`), + KEY `idx_access` (`access`), + KEY `idx_checkout` (`checked_out`), + KEY `idx_path` (`path`), + KEY `idx_left_right` (`lft`,`rgt`), + KEY `idx_alias` (`alias`), + KEY `idx_language` (`language`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `#__tags` +-- + +INSERT INTO `#__tags` (`id`, `parent_id`, `lft`, `rgt`, `level`, `path`, `title`, `alias`, `note`, `description`, `published`, `checked_out`, `checked_out_time`, `access`, `params`, `metadesc`, `metakey`, `metadata`, `created_user_id`, `created_time`,`created_by_alias`, `modified_user_id`, `modified_time`, `images`, `urls`, `hits`, `language`, `version`) +VALUES (1, 0, 0, 1, 0, '', 'ROOT', 'root', '', '', 1, 0, '0000-00-00 00:00:00', 1, '{}', '', '', '', '', '2011-01-01 00:00:01','', 0, '0000-00-00 00:00:00', '', '', 0, '*', 1); + +-- +-- Table structure for table `#__ucm_base` +-- + +CREATE TABLE IF NOT EXISTS `#__ucm_base` ( + `ucm_id` int(10) unsigned NOT NULL, + `ucm_item_id` int(10) NOT NULL, + `ucm_type_id` int(11) NOT NULL, + `ucm_language_id` int(11) NOT NULL, + PRIMARY KEY (`ucm_id`), + KEY `idx_ucm_item_id` (`ucm_item_id`), + KEY `idx_ucm_type_id` (`ucm_type_id`), + KEY `idx_ucm_language_id` (`ucm_language_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `#__ucm_content` ( + `core_content_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `core_type_alias` varchar(255) NOT NULL DEFAULT '' COMMENT 'FK to the content types table', + `core_title` varchar(255) NOT NULL, + `core_alias` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', + `core_body` mediumtext NOT NULL, + `core_state` tinyint(1) NOT NULL DEFAULT '0', + `core_checked_out_time` varchar(255) NOT NULL DEFAULT '', + `core_checked_out_user_id` int(10) unsigned NOT NULL DEFAULT '0', + `core_access` int(10) unsigned NOT NULL DEFAULT '0', + `core_params` text NOT NULL, + `core_featured` tinyint(4) unsigned NOT NULL DEFAULT '0', + `core_metadata` varchar(2048) NOT NULL COMMENT 'JSON encoded metadata properties.', + `core_created_user_id` int(10) unsigned NOT NULL DEFAULT '0', + `core_created_by_alias` varchar(255) NOT NULL DEFAULT '', + `core_created_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `core_modified_user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Most recent user that modified', + `core_modified_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `core_language` char(7) NOT NULL, + `core_publish_up` datetime NOT NULL, + `core_publish_down` datetime NOT NULL, + `core_content_item_id` int(10) unsigned COMMENT 'ID from the individual type table', + `asset_id` int(10) unsigned COMMENT 'FK to the #__assets table.', + `core_images` text NOT NULL, + `core_urls` text NOT NULL, + `core_hits` int(10) unsigned NOT NULL DEFAULT '0', + `core_version` int(10) unsigned NOT NULL DEFAULT '1', + `core_ordering` int(11) NOT NULL DEFAULT '0', + `core_metakey` text NOT NULL, + `core_metadesc` text NOT NULL, + `core_catid` int(10) unsigned NOT NULL DEFAULT '0', + `core_xreference` varchar(50) NOT NULL COMMENT 'A reference to enable linkages to external data sets.', + `core_type_id` int(10) unsigned, + PRIMARY KEY (`core_content_id`), + KEY `tag_idx` (`core_state`,`core_access`), + KEY `idx_access` (`core_access`), + KEY `idx_alias` (`core_alias`), + KEY `idx_language` (`core_language`), + KEY `idx_title` (`core_title`), + KEY `idx_modified_time` (`core_modified_time`), + KEY `idx_created_time` (`core_created_time`), + KEY `idx_content_type` (`core_type_alias`), + KEY `idx_core_modified_user_id` (`core_modified_user_id`), + KEY `idx_core_checked_out_user_id` (`core_checked_out_user_id`), + KEY `idx_core_created_user_id` (`core_created_user_id`), + KEY `idx_core_type_id` (`core_type_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Contains core content data in name spaced fields'; + +INSERT INTO `#__extensions` (`extension_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `custom_data`, `system_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES +(29, 'com_tags', 'component', 'com_tags', '', 1, 1, 1, 1, '{"legacy":false,"name":"com_tags","type":"component","creationDate":"March 2013","author":"Joomla! Project","copyright":"(C) 2005 - 2013 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"3.0.0","description":"COM_TAGS_XML_DESCRIPTION","group":""}', '{}', '', '', 0, '0000-00-00 00:00:00', 0, 0), +(316, 'mod_tags_popular', 'module', 'mod_tags_popular', '', 0, 1, 1, 0, '{"name":"mod_tags_popular","type":"module","creationDate":"January 2013","author":"Joomla! Project","copyright":"Copyright (C) 2005 - 2013 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"3.1.0","description":"MOD_TAGS_POPULAR_XML_DESCRIPTION","group":""}', '{"maximum":"5","timeframe":"alltime","owncache":"1"}', '', '', 0, '0000-00-00 00:00:00', 0, 0), +(317, 'mod_tags_similar', 'module', 'mod_tags_similar', '', 0, 1, 1, 0, '{"name":"mod_tags_similar","type":"module","creationDate":"January 2013","author":"Joomla! Project","copyright":"Copyright (C) 2005 - 2013 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"3.1.0","description":"MOD_TAGS_SIMILAR_XML_DESCRIPTION","group":""}', '{"maximum":"5","matchtype":"any","owncache":"1"}', '', '', 0, '0000-00-00 00:00:00', 0, 0), +(447, 'plg_finder_tags', 'plugin', 'tags', 'finder', 0, 1, 1, 0, '{"name":"plg_finder_tags","type":"plugin","creationDate":"February 2013","author":"Joomla! Project","copyright":"(C) 2005 - 2013 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"3.0.0","description":"PLG_FINDER_TAGS_XML_DESCRIPTION","group":""}', '{}', '', '', 0, '0000-00-00 00:00:00', 0, 0); + +INSERT INTO `#__menu` (`id`, `menutype`, `title`, `alias`, `note`, `path`, `link`, `type`, `published`, `parent_id`, `level`, `component_id`, `checked_out`, `checked_out_time`, `browserNav`, `access`, `img`, `template_style_id`, `params`, `lft`, `rgt`, `home`, `language`, `client_id`) VALUES +(23, 'main', 'com_tags', 'Tags', '', 'Tags', 'index.php?option=com_tags', 'component', 0, 1, 1, 29, 0, '0000-00-00 00:00:00', 0, 1, 'class:tags', 0, '', 45, 46, 0, '', 1); diff --git a/administrator/components/com_admin/sql/updates/mysql/3.1.1.sql b/administrator/components/com_admin/sql/updates/mysql/3.1.1.sql new file mode 100644 index 0000000..df442fa --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/3.1.1.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.1.1 \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/mysql/3.1.2.sql b/administrator/components/com_admin/sql/updates/mysql/3.1.2.sql new file mode 100644 index 0000000..8c09a7f --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/3.1.2.sql @@ -0,0 +1,11 @@ +UPDATE `#__content_types` SET `table` = '{"special":{"dbtable":"#__content","key":"id","type":"Content","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE `type_title` = 'Article';UPDATE `#__content_types` SET `table` = '{"special":{"dbtable":"#__weblinks","key":"id","type":"Weblink","prefix":"WeblinksTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE `type_title` = 'Weblink';UPDATE `#__content_types` SET `table` = '{"special":{"dbtable":"#__contact_details","key":"id","type":"Contact","prefix":"ContactTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE `type_title` = 'Contact';UPDATE `#__content_types` SET `table` = '{"special":{"dbtable":"#__newsfeeds","key":"id","type":"Newsfeed","prefix":"NewsfeedsTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE `type_title` = 'Newsfeed';UPDATE `#__content_types` SET `table` = '{"special":{"dbtable":"#__users","key":"id","type":"User","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE `type_title` = 'User';UPDATE `#__content_types` SET `table` = '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE `type_title` = 'Article Category';UPDATE `#__content_types` SET `table` = '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE `type_title` = 'Contact Category';UPDATE `#__content_types` SET `table` = '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE `type_title` = 'Newsfeeds Category';UPDATE `#__content_types` SET `table` = '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE `type_title` = 'Weblinks Category';UPDATE `#__content_types` SET `table` = '{"special":{"dbtable":"#__tags","key":"tag_id","type":"Tag","prefix":"TagsTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE `type_title` = 'Tag'; +UPDATE `#__content_types` SET `field_mappings` = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"introtext", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"attribs", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"asset_id"}, "special": {"fulltext":"fulltext"}}' WHERE `type_id` = '1'; +UPDATE `#__content_types` SET `field_mappings` = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"description", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"url", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}, "special": {}}' WHERE `type_id` = '2'; +UPDATE `#__content_types` SET `field_mappings` = '{"common":{"core_content_item_id":"id","core_title":"name","core_state":"published","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"address", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"image", "core_urls":"webpage", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}, "special": {"con_position":"con_position","suburb":"suburb","state":"state","country":"country","postcode":"postcode","telephone":"telephone","fax":"fax","misc":"misc","email_to":"email_to","default_con":"default_con","user_id":"user_id","mobile":"mobile","sortname1":"sortname1","sortname2":"sortname2","sortname3":"sortname3"}}' WHERE `type_id` = '3'; +UPDATE `#__content_types` SET `field_mappings` = '{"common":{"core_content_item_id":"id","core_title":"name","core_state":"published","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"description", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"link", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}, "special": {"numarticles":"numarticles","cache_time":"cache_time","rtl":"rtl"}}' WHERE `type_id` = '4'; +UPDATE `#__content_types` SET `field_mappings` = '{"common":{"core_content_item_id":"id","core_title":"name","core_state":"null","core_alias":"username","core_created_time":"registerdate","core_modified_time":"lastvisitDate","core_body":"null", "core_hits":"null","core_publish_up":"null","core_publish_down":"null","access":"null", "core_params":"params", "core_featured":"null", "core_metadata":"null", "core_language":"null", "core_images":"null", "core_urls":"null", "core_version":"null", "core_ordering":"null", "core_metakey":"null", "core_metadesc":"null", "core_catid":"null", "core_xreference":"null", "asset_id":"null"}, "special": {}}' WHERE `type_id` = '5'; +UPDATE `#__content_types` SET `field_mappings` = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}' WHERE `type_id` = '6'; +UPDATE `#__content_types` SET `field_mappings` = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}' WHERE `type_id` = '7'; +UPDATE `#__content_types` SET `field_mappings` = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}' WHERE `type_id` = '8'; +UPDATE `#__content_types` SET `field_mappings` = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}' WHERE `type_id` = '9'; +UPDATE `#__content_types` SET `field_mappings` = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"null", "core_xreference":"null", "asset_id":"null"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path"}}' WHERE `type_id` = '10'; diff --git a/administrator/components/com_admin/sql/updates/mysql/3.1.3.sql b/administrator/components/com_admin/sql/updates/mysql/3.1.3.sql new file mode 100644 index 0000000..ebc1102 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/3.1.3.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.1.3 diff --git a/administrator/components/com_admin/sql/updates/mysql/3.1.4.sql b/administrator/components/com_admin/sql/updates/mysql/3.1.4.sql new file mode 100644 index 0000000..e4bba83 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/3.1.4.sql @@ -0,0 +1,2 @@ +INSERT INTO `#__extensions` (`extension_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `custom_data`, `system_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES +(104, 'IDNA Convert', 'library', 'idna_convert', '', 0, 1, 1, 1, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0); diff --git a/administrator/components/com_admin/sql/updates/mysql/3.1.5.sql b/administrator/components/com_admin/sql/updates/mysql/3.1.5.sql new file mode 100644 index 0000000..2c9caba --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/3.1.5.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.1.5 diff --git a/administrator/components/com_admin/sql/updates/mysql/index.html b/administrator/components/com_admin/sql/updates/mysql/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/sql/updates/postgresql/3.0.0.sql b/administrator/components/com_admin/sql/updates/postgresql/3.0.0.sql new file mode 100644 index 0000000..9a6e816 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/3.0.0.sql @@ -0,0 +1 @@ +-- Placeholder file for database changes for version 3.0.0 \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/postgresql/3.0.1.sql b/administrator/components/com_admin/sql/updates/postgresql/3.0.1.sql new file mode 100644 index 0000000..c9f8fda --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/3.0.1.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.0.1 \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/postgresql/3.0.2.sql b/administrator/components/com_admin/sql/updates/postgresql/3.0.2.sql new file mode 100644 index 0000000..df708fc --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/3.0.2.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.0.2 \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/postgresql/3.0.3.sql b/administrator/components/com_admin/sql/updates/postgresql/3.0.3.sql new file mode 100644 index 0000000..45c4e62 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/3.0.3.sql @@ -0,0 +1 @@ +ALTER TABLE "#__associations" ALTER COLUMN id TYPE INT(11); \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/postgresql/3.1.0.sql b/administrator/components/com_admin/sql/updates/postgresql/3.1.0.sql new file mode 100644 index 0000000..0cd4fed --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/3.1.0.sql @@ -0,0 +1,198 @@ +/* Changes to tables where data type conflicts exist with MySQL (mainly dealing with null values */ +ALTER TABLE "#__modules" ALTER COLUMN "content" SET DEFAULT ''; +ALTER TABLE "#__updates" ALTER COLUMN "data" SET DEFAULT ''; + +/* Tags database schema */ + +-- +-- Table: #__content_types +-- +CREATE TABLE "#__content_types" ( + "type_id" serial NOT NULL, + "type_title" character varying(255) NOT NULL DEFAULT '', + "type_alias" character varying(255) NOT NULL DEFAULT '', + "table" character varying(255) NOT NULL DEFAULT '', + "rules" text NOT NULL, + "field_mappings" text NOT NULL, + "router" character varying(255) NOT NULL DEFAULT '', + PRIMARY KEY ("type_id") +); +CREATE INDEX "#__content_types_idx_alias" ON "#__content_types" ("type_alias"); + +-- +-- Dumping data for table #__content_types +-- +INSERT INTO "#__content_types" ("type_id", "type_title", "type_alias", "table", "rules", "field_mappings", "router") VALUES +(1, 'Article', 'com_content.article', '{"special":{"dbtable":"#__content","key":"id","type":"Content","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"introtext", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"attribs", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"asset_id"}], "special": [{"fulltext":"fulltext"}]}','ContentHelperRoute::getArticleRoute'), +(2, 'Weblink', 'com_weblinks.weblink', '{"special":{"dbtable":"#__weblinks","key":"id","type":"Weblink","prefix":"WeblinksTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"description", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}], "special": []}','WeblinksHelperRoute::getWeblinkRoute'), +(3, 'Contact', 'com_contact.contact', '{"special":{"dbtable":"#__contact_details","key":"id","type":"Contact","prefix":"ContactTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"name","core_state":"published","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"address", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"image", "core_urls":"webpage", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}], "special": [{"con_position":"con_position","suburb":"suburb","state":"state","country":"country","postcode":"postcode","telephone":"telephone","fax":"fax","misc":"misc","email_to":"email_to","default_con":"default_con","user_id":"user_id","mobile":"mobile","sortname1":"sortname1","sortname2":"sortname2","sortname3":"sortname3"}]}','ContactHelperRoute::getContactRoute'), +(4, 'Newsfeed', 'com_newsfeeds.newsfeed', '{"special":{"dbtable":"#__newsfeeds","key":"id","type":"Newsfeed","prefix":"NewsfeedsTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"name","core_state":"published","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"description", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"link", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}], "special": [{"numarticles":"numarticles","cache_time":"cache_time","rtl":"rtl"}]}','NewsfeedsHelperRoute::getNewsfeedRoute'), +(5, 'User', 'com_users.user', '{"special":{"dbtable":"#__users","key":"id","type":"User","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"name","core_state":"null","core_alias":"username","core_created_time":"registerdate","core_modified_time":"lastvisitDate","core_body":"null", "core_hits":"null","core_publish_up":"null","core_publish_down":"null","access":"null", "core_params":"params", "core_featured":"null", "core_metadata":"null", "core_language":"null", "core_images":"null", "core_urls":"null", "core_version":"null", "core_ordering":"null", "core_metakey":"null", "core_metadesc":"null", "core_catid":"null", "core_xreference":"null", "asset_id":"null"}], "special": [{}]}','UsersHelperRoute::getUserRoute'), +(6, 'Article Category', 'com_content.category', '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}]}','ContentHelperRoute::getCategoryRoute'), +(7, 'Contact Category', 'com_contact.category', '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}]}','ContactHelperRoute::getCategoryRoute'), +(8, 'Newsfeeds Category', 'com_newsfeeds.category', '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}]}','NewsfeedsHelperRoute::getCategoryRoute'), +(9, 'Weblinks Category', 'com_weblinks.category', '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}]}','WeblinksHelperRoute::getCategoryRoute'), +(10, 'Tag', 'com_tags.tag', '{"special":{"dbtable":"#__tags","key":"tag_id","type":"Tag","prefix":"TagsTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}', '', '{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"null", "core_xreference":"null", "asset_id":"null"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path"}]}','TagsHelperRoute::getTagRoute'); + +SELECT nextval('#__content_types_type_id_seq'); +SELECT setval('#__content_types_type_id_seq', 10000, false); + +-- +-- Table: #__contentitem_tag_map +-- +CREATE TABLE "#__contentitem_tag_map" ( + "type_alias" character varying(255) NOT NULL DEFAULT '', + "core_content_id" integer NOT NULL, + "content_item_id" integer NOT NULL, + "tag_id" integer NOT NULL, + "tag_date" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + CONSTRAINT "uc_ItemnameTagid" UNIQUE ("type_alias", "content_item_id", "tag_id") +); + +CREATE INDEX "#__contentitem_tag_map_idx_tag_name" ON "#__contentitem_tag_map" ("tag_id", "type_alias"); +CREATE INDEX "#__contentitem_tag_map_idx_date_id" ON "#__contentitem_tag_map" ("tag_date", "tag_id"); +CREATE INDEX "#__contentitem_tag_map_idx_tag" ON "#__contentitem_tag_map" ("tag_id"); +CREATE INDEX "#__contentitem_tag_map_idx_core_content_id" ON "#__contentitem_tag_map" ("core_content_id"); + +COMMENT ON COLUMN "#__contentitem_tag_map"."core_content_id" IS 'PK from the core content table'; +COMMENT ON COLUMN "#__contentitem_tag_map"."content_item_id" IS 'PK from the content type table'; +COMMENT ON COLUMN "#__contentitem_tag_map"."tag_id" IS 'PK from the tag table'; +COMMENT ON COLUMN "#__contentitem_tag_map"."tag_date" IS 'Date of most recent save for this tag-item'; + +-- -------------------------------------------------------- + +-- +-- Table: #__tags +-- +CREATE TABLE "#__tags" ( + "id" serial NOT NULL, + "parent_id" bigint DEFAULT 0 NOT NULL, + "lft" bigint DEFAULT 0 NOT NULL, + "rgt" bigint DEFAULT 0 NOT NULL, + "level" integer DEFAULT 0 NOT NULL, + "path" character varying(255) DEFAULT '' NOT NULL, + "title" character varying(255) NOT NULL, + "alias" character varying(255) DEFAULT '' NOT NULL, + "note" character varying(255) DEFAULT '' NOT NULL, + "description" text DEFAULT '' NOT NULL, + "published" smallint DEFAULT 0 NOT NULL, + "checked_out" bigint DEFAULT 0 NOT NULL, + "checked_out_time" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "access" bigint DEFAULT 0 NOT NULL, + "params" text NOT NULL, + "metadesc" character varying(1024) NOT NULL, + "metakey" character varying(1024) NOT NULL, + "metadata" character varying(2048) NOT NULL, + "created_user_id" integer DEFAULT 0 NOT NULL, + "created_time" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "created_by_alias" character varying(255) DEFAULT '' NOT NULL, + "modified_user_id" integer DEFAULT 0 NOT NULL, + "modified_time" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "images" text NOT NULL, + "urls" text NOT NULL, + "hits" integer DEFAULT 0 NOT NULL, + "language" character varying(7) DEFAULT '' NOT NULL, + "version" bigint DEFAULT 1 NOT NULL, + "publish_up" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "publish_down" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "#__tags_cat_idx" ON "#__tags" ("published", "access"); +CREATE INDEX "#__tags_idx_access" ON "#__tags" ("access"); +CREATE INDEX "#__tags_idx_checkout" ON "#__tags" ("checked_out"); +CREATE INDEX "#__tags_idx_path" ON "#__tags" ("path"); +CREATE INDEX "#__tags_idx_left_right" ON "#__tags" ("lft", "rgt"); +CREATE INDEX "#__tags_idx_alias" ON "#__tags" ("alias"); +CREATE INDEX "#__tags_idx_language" ON "#__tags" ("language"); + +-- +-- Dumping data for table #__tags +-- + +INSERT INTO "#__tags" ("id", "parent_id", "lft", "rgt", "level", "path", "title", "alias", "note", "description", "published", "checked_out", "checked_out_time", "access", "params", "metadesc", "metakey", "metadata", "created_user_id", "created_time", "created_by_alias", "modified_user_id", "modified_time", "images", "urls", "hits", "language", "version") VALUES +(1, 0, 0, 1, 0, '', 'ROOT', 'root', '', '', 1, 0, '1970-01-01 00:00:00', 1, '{}', '', '', '', 42, '1970-01-01 00:00:00', '', 0, '1970-01-01 00:00:00', '', '', 0, '*', 1); + +SELECT nextval('#__tags_id_seq'); +SELECT setval('#__tags_id_seq', 2, false); + +-- +-- Table: #__ucm_base +-- +CREATE TABLE "#__ucm_base" ( + "ucm_id" serial NOT NULL, + "ucm_item_id" bigint NOT NULL, + "ucm_type_id" bigint NOT NULL, + "ucm_language_id" bigint NOT NULL, + PRIMARY KEY ("ucm_id") +); +CREATE INDEX "#__ucm_base_ucm_item_id" ON "#__ucm_base" ("ucm_item_id"); +CREATE INDEX "#__ucm_base_ucm_type_id" ON "#__ucm_base" ("ucm_type_id"); +CREATE INDEX "#__ucm_base_ucm_language_id" ON "#__ucm_base" ("ucm_language_id"); + +-- +-- Table: #__ucm_content +-- +CREATE TABLE "#__ucm_content" ( + "core_content_id" serial NOT NULL, + "core_type_alias" character varying(255) DEFAULT '' NOT NULL, + "core_title" character varying(255) NOT NULL, + "core_alias" character varying(255) DEFAULT '' NOT NULL, + "core_body" text NOT NULL, + "core_state" smallint DEFAULT 0 NOT NULL, + "core_checked_out_time" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "core_checked_out_user_id" bigint DEFAULT 0 NOT NULL, + "core_access" bigint DEFAULT 0 NOT NULL, + "core_params" text NOT NULL, + "core_featured" smallint DEFAULT 0 NOT NULL, + "core_metadata" text NOT NULL, + "core_created_user_id" bigint DEFAULT 0 NOT NULL, + "core_created_by_alias" character varying(255) DEFAULT '' NOT NULL, + "core_created_time" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "core_modified_user_id" bigint DEFAULT 0 NOT NULL, + "core_modified_time" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "core_language" character varying(7) DEFAULT '' NOT NULL, + "core_publish_up" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "core_publish_down" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "core_content_item_id" bigint DEFAULT 0 NOT NULL, + "asset_id" bigint DEFAULT 0 NOT NULL, + "core_images" text NOT NULL, + "core_urls" text NOT NULL, + "core_hits" bigint DEFAULT 0 NOT NULL, + "core_version" bigint DEFAULT 1 NOT NULL, + "core_ordering" bigint DEFAULT 0 NOT NULL, + "core_metakey" text NOT NULL, + "core_metadesc" text NOT NULL, + "core_catid" bigint DEFAULT 0 NOT NULL, + "core_xreference" character varying(50) DEFAULT '' NOT NULL, + "core_type_id" bigint DEFAULT 0 NOT NULL, + PRIMARY KEY ("core_content_id"), + CONSTRAINT "#__ucm_content_idx_type_alias_item_id" UNIQUE ("core_type_alias", "core_content_item_id") +); +CREATE INDEX "#__ucm_content_tag_idx" ON "#__ucm_content" ("core_state", "core_access"); +CREATE INDEX "#__ucm_content_idx_access" ON "#__ucm_content" ("core_access"); +CREATE INDEX "#__ucm_content_idx_alias" ON "#__ucm_content" ("core_alias"); +CREATE INDEX "#__ucm_content_idx_language" ON "#__ucm_content" ("core_language"); +CREATE INDEX "#__ucm_content_idx_title" ON "#__ucm_content" ("core_title"); +CREATE INDEX "#__ucm_content_idx_modified_time" ON "#__ucm_content" ("core_modified_time"); +CREATE INDEX "#__ucm_content_idx_created_time" ON "#__ucm_content" ("core_created_time"); +CREATE INDEX "#__ucm_content_idx_content_type" ON "#__ucm_content" ("core_type_alias"); +CREATE INDEX "#__ucm_content_idx_core_modified_user_id" ON "#__ucm_content" ("core_modified_user_id"); +CREATE INDEX "#__ucm_content_idx_core_checked_out_user_id" ON "#__ucm_content" ("core_checked_out_user_id"); +CREATE INDEX "#__ucm_content_idx_core_created_user_id" ON "#__ucm_content" ("core_created_user_id"); +CREATE INDEX "#__ucm_content_idx_core_type_id" ON "#__ucm_content" ("core_type_id"); + +-- +-- Add extensions table records +-- +INSERT INTO "#__extensions" ("extension_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "custom_data", "system_data", "checked_out", "checked_out_time", "ordering", "state") VALUES +(29, 'com_tags', 'component', 'com_tags', '', 1, 1, 1, 1, '{"legacy":false,"name":"com_tags","type":"component","creationDate":"March 2013","author":"Joomla! Project","copyright":"(C) 2005 - 2013 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"3.0.0","description":"COM_TAGS_XML_DESCRIPTION","group":""}', '{}', '', '', 0, '1970-01-01 00:00:00', 0, 0), +(315, 'mod_stats_admin', 'module', 'mod_stats_admin', '', 1, 1, 1, 0, '{"name":"mod_stats_admin","type":"module","creationDate":"September 2012","author":"Joomla! Project","copyright":"Copyright (C) 2005 - 2013 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"3.0.0","description":"MOD_STATS_XML_DESCRIPTION","group":""}', '{"serverinfo":"0","siteinfo":"0","counter":"0","increase":"0","cache":"1","cache_time":"900","cachemode":"static"}', '', '', 0, '1970-01-01 00:00:00', 0, 0), +(316, 'mod_tags_popular', 'module', 'mod_tags_popular', '', 0, 1, 1, 0, '{"name":"mod_tags_popular","type":"module","creationDate":"January 2013","author":"Joomla! Project","copyright":"Copyright (C) 2005 - 2013 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"3.1.0","description":"MOD_TAGS_POPULAR_XML_DESCRIPTION","group":""}', '{"maximum":"5","timeframe":"alltime","owncache":"1"}', '', '', 0, '1970-01-01 00:00:00', 0, 0), +(317, 'mod_tags_similar', 'module', 'mod_tags_similar', '', 0, 1, 1, 0, '{"name":"mod_tags_similar","type":"module","creationDate":"January 2013","author":"Joomla! Project","copyright":"Copyright (C) 2005 - 2013 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"3.1.0","description":"MOD_TAGS_SIMILAR_XML_DESCRIPTION","group":""}', '{"maximum":"5","matchtype":"any","owncache":"1"}', '', '', 0, '1970-01-01 00:00:00', 0, 0), +(447, 'plg_finder_tags', 'plugin', 'tags', 'finder', 0, 1, 1, 0, '{"name":"plg_finder_tags","type":"plugin","creationDate":"February 2013","author":"Joomla! Project","copyright":"(C) 2005 - 2013 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"3.0.0","description":"PLG_FINDER_TAGS_XML_DESCRIPTION","group":""}', '{}', '', '', 0, '1970-01-01 00:00:00', 0, 0); + +-- +-- Add menu table records +-- +INSERT INTO "#__menu" ( "id", "menutype", "title", "alias", "note", "path", "link", "type", "published", "parent_id", "level", "component_id", "checked_out", "checked_out_time", "browserNav", "access", "img", "template_style_id", "params", "lft", "rgt", "home", "language", "client_id") VALUES +(23, 'main', 'com_tags', 'Tags', '', 'Tags', 'index.php?option=com_tags', 'component', 0, 1, 1, 29, 0, '1970-01-01 00:00:00', 0, 1, 'class:tags', 0, '', 45, 46, 0, '', 1); diff --git a/administrator/components/com_admin/sql/updates/postgresql/3.1.1.sql b/administrator/components/com_admin/sql/updates/postgresql/3.1.1.sql new file mode 100644 index 0000000..df442fa --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/3.1.1.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.1.1 \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/postgresql/3.1.2.sql b/administrator/components/com_admin/sql/updates/postgresql/3.1.2.sql new file mode 100644 index 0000000..8b68c07 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/3.1.2.sql @@ -0,0 +1,11 @@ +UPDATE "#__content_types" SET "table" = '{"special":{"dbtable":"#__content","key":"id","type":"Content","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE "type_title" = 'Article';UPDATE "#__content_types" SET "table" = '{"special":{"dbtable":"#__weblinks","key":"id","type":"Weblink","prefix":"WeblinksTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE "type_title" = 'Weblink';UPDATE "#__content_types" SET "table" = '{"special":{"dbtable":"#__contact_details","key":"id","type":"Contact","prefix":"ContactTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE "type_title" = 'Contact';UPDATE "#__content_types" SET "table" = '{"special":{"dbtable":"#__newsfeeds","key":"id","type":"Newsfeed","prefix":"NewsfeedsTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE "type_title" = 'Newsfeed';UPDATE "#__content_types" SET "table" = '{"special":{"dbtable":"#__users","key":"id","type":"User","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE "type_title" = 'User';UPDATE "#__content_types" SET "table" = '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE "type_title" = 'Article Category';UPDATE "#__content_types" SET "table" = '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE "type_title" = 'Contact Category';UPDATE "#__content_types" SET "table" = '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE "type_title" = 'Newsfeeds Category';UPDATE "#__content_types" SET "table" = '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE "type_title" = 'Weblinks Category';UPDATE "#__content_types" SET "table" = '{"special":{"dbtable":"#__tags","key":"tag_id","type":"Tag","prefix":"TagsTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE "type_title" = 'Tag'; +UPDATE "#__content_types" SET "field_mappings" = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"introtext", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"attribs", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"asset_id"}, "special": {"fulltext":"fulltext"}}' WHERE "type_id" = '1'; +UPDATE "#__content_types" SET "field_mappings" = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"description", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"url", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}, "special": {}}' WHERE "type_id" = '2'; +UPDATE "#__content_types" SET "field_mappings" = '{"common":{"core_content_item_id":"id","core_title":"name","core_state":"published","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"address", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"image", "core_urls":"webpage", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}, "special": {"con_position":"con_position","suburb":"suburb","state":"state","country":"country","postcode":"postcode","telephone":"telephone","fax":"fax","misc":"misc","email_to":"email_to","default_con":"default_con","user_id":"user_id","mobile":"mobile","sortname1":"sortname1","sortname2":"sortname2","sortname3":"sortname3"}}' WHERE "type_id" = '3'; +UPDATE "#__content_types" SET "field_mappings" = '{"common":{"core_content_item_id":"id","core_title":"name","core_state":"published","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"description", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"link", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}, "special": {"numarticles":"numarticles","cache_time":"cache_time","rtl":"rtl"}}' WHERE "type_id" = '4'; +UPDATE "#__content_types" SET "field_mappings" = '{"common":{"core_content_item_id":"id","core_title":"name","core_state":"null","core_alias":"username","core_created_time":"registerdate","core_modified_time":"lastvisitDate","core_body":"null", "core_hits":"null","core_publish_up":"null","core_publish_down":"null","access":"null", "core_params":"params", "core_featured":"null", "core_metadata":"null", "core_language":"null", "core_images":"null", "core_urls":"null", "core_version":"null", "core_ordering":"null", "core_metakey":"null", "core_metadesc":"null", "core_catid":"null", "core_xreference":"null", "asset_id":"null"}, "special": {}}' WHERE "type_id" = '5'; +UPDATE "#__content_types" SET "field_mappings" = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}' WHERE "type_id" = '6'; +UPDATE "#__content_types" SET "field_mappings" = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}' WHERE "type_id" = '7'; +UPDATE "#__content_types" SET "field_mappings" = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}' WHERE "type_id" = '8'; +UPDATE "#__content_types" SET "field_mappings" = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}' WHERE "type_id" = '9'; +UPDATE "#__content_types" SET "field_mappings" = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"null", "core_xreference":"null", "asset_id":"null"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path"}}' WHERE "type_id" = '10'; diff --git a/administrator/components/com_admin/sql/updates/postgresql/3.1.3.sql b/administrator/components/com_admin/sql/updates/postgresql/3.1.3.sql new file mode 100644 index 0000000..ebc1102 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/3.1.3.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.1.3 diff --git a/administrator/components/com_admin/sql/updates/postgresql/3.1.4.sql b/administrator/components/com_admin/sql/updates/postgresql/3.1.4.sql new file mode 100644 index 0000000..6014cdb --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/3.1.4.sql @@ -0,0 +1,2 @@ +INSERT INTO "#__extensions" ("extension_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "custom_data", "system_data", "checked_out", "checked_out_time", "ordering", "state") VALUES +(104, 'IDNA Convert', 'library', 'idna_convert', '', 0, 1, 1, 1, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0); diff --git a/administrator/components/com_admin/sql/updates/postgresql/3.1.5.sql b/administrator/components/com_admin/sql/updates/postgresql/3.1.5.sql new file mode 100644 index 0000000..2c9caba --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/3.1.5.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.1.5 diff --git a/administrator/components/com_admin/sql/updates/postgresql/index.html b/administrator/components/com_admin/sql/updates/postgresql/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/sql/updates/sqlazure/2.5.2-2012-03-05.sql b/administrator/components/com_admin/sql/updates/sqlazure/2.5.2-2012-03-05.sql new file mode 100644 index 0000000..1c06a39 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/2.5.2-2012-03-05.sql @@ -0,0 +1 @@ +# Dummy SQL file to set schema version \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/sqlazure/2.5.3-2012-03-13.sql b/administrator/components/com_admin/sql/updates/sqlazure/2.5.3-2012-03-13.sql new file mode 100644 index 0000000..1c06a39 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/2.5.3-2012-03-13.sql @@ -0,0 +1 @@ +# Dummy SQL file to set schema version \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/sqlazure/2.5.4-2012-03-18.sql b/administrator/components/com_admin/sql/updates/sqlazure/2.5.4-2012-03-18.sql new file mode 100644 index 0000000..b64d3ad --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/2.5.4-2012-03-18.sql @@ -0,0 +1,13 @@ +SET IDENTITY_INSERT #__extensions ON; + +INSERT INTO #__extensions (extension_id, name, type, element, folder, client_id, enabled, access, protected, manifest_cache, params, custom_data, system_data, checked_out, checked_out_time, ordering, state) +SELECT 28, 'com_joomlaupdate', 'component', 'com_joomlaupdate', '', 1, 1, 0, 1, '{"legacy":false,"name":"com_joomlaupdate","type":"component","creationDate":"February 2012","author":"Joomla! Project","copyright":"(C) 2005 - 2012 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"2.5.2","description":"COM_JOOMLAUPDATE_XML_DESCRIPTION","group":""}', '{}', '', '', 0, '1900-01-01 00:00:00', 0, 0; + +SET IDENTITY_INSERT #__extensions OFF; + +SET IDENTITY_INSERT #__menu ON; + +INSERT INTO #__menu (id, menutype, title, alias, note, path, link, type, published, parent_id, level, component_id, ordering, checked_out, checked_out_time, browserNav, access, img, template_style_id, params, lft, rgt, home, language, client_id) +SELECT 22, 'menu', 'com_joomlaupdate', 'Joomla! Update', '', 'Joomla! Update', 'index.php?option=com_joomlaupdate', 'component', 0, 1, 1, 28, 0, 0, '1900-01-01 00:00:00', 0, 0, 'class:joomlaupdate', 0, '', 41, 42, 0, '*', 1; + +SET IDENTITY_INSERT #__menu OFF; diff --git a/administrator/components/com_admin/sql/updates/sqlazure/2.5.4-2012-03-19.sql b/administrator/components/com_admin/sql/updates/sqlazure/2.5.4-2012-03-19.sql new file mode 100644 index 0000000..32d0da6 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/2.5.4-2012-03-19.sql @@ -0,0 +1,7 @@ +ALTER TABLE [#__languages] ADD [access] INTEGER CONSTRAINT DF_languages_access DEFAULT '' NOT NULL + +CREATE UNIQUE INDEX idx_access ON [jos_languages] (access); + +UPDATE [#__categories] SET extension = 'com_users.notes' WHERE extension = 'com_users'; + +UPDATE [#__extensions] SET enabled = '1' WHERE protected = '1' AND [type] <> 'plugin'; diff --git a/administrator/components/com_admin/sql/updates/sqlazure/2.5.5.sql b/administrator/components/com_admin/sql/updates/sqlazure/2.5.5.sql new file mode 100644 index 0000000..d85ed92 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/2.5.5.sql @@ -0,0 +1,3 @@ +ALTER TABLE [#__redirect_links] ADD [hits] INTEGER CONSTRAINT DF_redirect_links_hits DEFAULT '' NOT NULL; +ALTER TABLE [#__users] ADD [lastResetTime] [datetime] NOT NULL; +ALTER TABLE [#__users] ADD [resetCount] [int] NOT NULL; \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/sqlazure/2.5.6.sql b/administrator/components/com_admin/sql/updates/sqlazure/2.5.6.sql new file mode 100644 index 0000000..ff1afae --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/2.5.6.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 2.5.6 \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/sqlazure/2.5.7.sql b/administrator/components/com_admin/sql/updates/sqlazure/2.5.7.sql new file mode 100644 index 0000000..17b691a --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/2.5.7.sql @@ -0,0 +1 @@ +INSERT INTO #__update_sites (name, type, location, enabled, last_check_timestamp) VALUES ('Accredited Joomla! Translations', 'collection', 'http://update.joomla.org/language/translationlist.xml', 1, 0);INSERT INTO #__update_sites_extensions (update_site_id, extension_id) VALUES (SCOPE_IDENTITY(), 600);UPDATE [#__assets] SET name=REPLACE( name, 'com_user.notes.category','com_users.category' );UPDATE [#__categories] SET extension=REPLACE( extension, 'com_user.notes.category','com_users.category' ); \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/sqlazure/3.0.0.sql b/administrator/components/com_admin/sql/updates/sqlazure/3.0.0.sql new file mode 100644 index 0000000..b2aa72c --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/3.0.0.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.0.0 diff --git a/administrator/components/com_admin/sql/updates/sqlazure/3.0.1.sql b/administrator/components/com_admin/sql/updates/sqlazure/3.0.1.sql new file mode 100644 index 0000000..d1c1420 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/3.0.1.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.0.1 diff --git a/administrator/components/com_admin/sql/updates/sqlazure/3.0.2.sql b/administrator/components/com_admin/sql/updates/sqlazure/3.0.2.sql new file mode 100644 index 0000000..df708fc --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/3.0.2.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.0.2 \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/sqlazure/3.0.3.sql b/administrator/components/com_admin/sql/updates/sqlazure/3.0.3.sql new file mode 100644 index 0000000..da103bd --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/3.0.3.sql @@ -0,0 +1 @@ +ALTER TABLE #__associations ALTER COLUMN id INT; diff --git a/administrator/components/com_admin/sql/updates/sqlazure/3.1.0.sql b/administrator/components/com_admin/sql/updates/sqlazure/3.1.0.sql new file mode 100644 index 0000000..509df82 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/3.1.0.sql @@ -0,0 +1,336 @@ +/* Changes to Smart Search tables for driver compatibility */ +ALTER TABLE [#__finder_tokens_aggregate] ALTER COLUMN [term_id] [bigint] NULL; +ALTER TABLE [#__finder_tokens_aggregate] ALTER COLUMN [map_suffix] [nchar](1) NULL; +ALTER TABLE [#__finder_tokens_aggregate] ADD DEFAULT ((0)) FOR [term_id]; +ALTER TABLE [#__finder_tokens_aggregate] ADD DEFAULT ((0)) FOR [total_weight]; + +/* Changes to tables where data type conflicts exist with MySQL (mainly dealing with null values */ +ALTER TABLE [#__extensions] ADD DEFAULT (N'') FOR [system_data]; +ALTER TABLE [#__modules] ADD DEFAULT (N'') FOR [content]; +ALTER TABLE [#__updates] ADD DEFAULT (N'') FOR [data]; + +/* Tags database schema */ + +/****** Object: Table [#__content_types] ******/ +SET QUOTED_IDENTIFIER ON; + +CREATE TABLE [#__content_types]( + [type_id] [bigint] IDENTITY(1,1) NOT NULL, + [type_title] [nvarchar](255) NOT NULL DEFAULT '', + [type_alias] [nvarchar](255) NOT NULL DEFAULT '', + [table] [nvarchar](255) NOT NULL DEFAULT '', + [rules] [nvarchar](max) NOT NULL, + [field_mappings] [nvarchar](max) NOT NULL, + [router] [nvarchar](255) NOT NULL DEFAULT '', + CONSTRAINT [PK_#__content_types_type_id] PRIMARY KEY CLUSTERED +( + [type_id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY]; + +CREATE NONCLUSTERED INDEX [idx_alias] ON [#__content_types] +( + [type_alias] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +SET IDENTITY_INSERT #__content_types ON; + +INSERT INTO #__content_types ([type_id],[type_title],[type_alias],[table],[rules],[field_mappings],[router]) +SELECT 1,'Article','com_content.article','{"special":{"dbtable":"#__content","key":"id","type":"Content","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}','','{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"introtext", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"attribs", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"asset_id"}], "special": [{"fulltext":"fulltext"}]}','ContentHelperRoute::getArticleRoute' +UNION ALL +SELECT 2,'Weblink','com_weblinks.weblink','{"special":{"dbtable":"#__weblinks","key":"id","type":"Weblink","prefix":"WeblinksTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}','','{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"description", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}], "special": []}','WeblinksHelperRoute::getWeblinkRoute' +UNION ALL +SELECT 3,'Contact','com_contact.contact','{"special":{"dbtable":"#__contact_details","key":"id","type":"Contact","prefix":"ContactTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}','','{"common":[{"core_content_item_id":"id","core_title":"name","core_state":"published","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"address", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"image", "core_urls":"webpage", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}], "special": [{"con_position":"con_position","suburb":"suburb","state":"state","country":"country","postcode":"postcode","telephone":"telephone","fax":"fax","misc":"misc","email_to":"email_to","default_con":"default_con","user_id":"user_id","mobile":"mobile","sortname1":"sortname1","sortname2":"sortname2","sortname3":"sortname3"}]}','ContactHelperRoute::getContactRoute' +UNION ALL +SELECT 4,'Newsfeed','com_newsfeeds.newsfeed','{"special":{"dbtable":"#__newsfeeds","key":"id","type":"Newsfeed","prefix":"NewsfeedsTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}','','{"common":[{"core_content_item_id":"id","core_title":"name","core_state":"published","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"description", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"link", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}], "special": [{"numarticles":"numarticles","cache_time":"cache_time","rtl":"rtl"}]}','NewsfeedsHelperRoute::getNewsfeedRoute' +UNION ALL +SELECT 5,'User','com_users.user','{"special":{"dbtable":"#__users","key":"id","type":"User","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}','','{"common":[{"core_content_item_id":"id","core_title":"name","core_state":"null","core_alias":"username","core_created_time":"registerdate","core_modified_time":"lastvisitDate","core_body":"null", "core_hits":"null","core_publish_up":"null","core_publish_down":"null","access":"null", "core_params":"params", "core_featured":"null", "core_metadata":"null", "core_language":"null", "core_images":"null", "core_urls":"null", "core_version":"null", "core_ordering":"null", "core_metakey":"null", "core_metadesc":"null", "core_catid":"null", "core_xreference":"null", "asset_id":"null"}], "special": [{}]}','UsersHelperRoute::getUserRoute' +UNION ALL +SELECT 6,'Article Category','com_content.category','{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}','','{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}]}','ContentHelperRoute::getCategoryRoute' +UNION ALL +SELECT 7,'Contact Category','com_contact.category','{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}','','{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}]}','ContactHelperRoute::getCategoryRoute' +UNION ALL +SELECT 8,'Newsfeeds Category','com_newsfeeds.category','{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}','','{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}]}','NewsfeedsHelperRoute::getCategoryRoute' +UNION ALL +SELECT 9,'Weblinks Category','com_weblinks.category','{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}','','{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}]}','WeblinksHelperRoute::getCategoryRoute' +UNION ALL +SELECT 10,'Tag','com_tags.tag','{"special":{"dbtable":"#__tags","key":"tag_id","type":"Tag","prefix":"TagsTable","config":"array()"},"common":{"dbtable":"#__core_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}','','{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"null", "core_xreference":"null", "asset_id":"null"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path"}]}','TagsHelperRoute::getTagRoute'; + +SET IDENTITY_INSERT #__content_types OFF; + + +/****** Object: Table [#__contentitem_tag_map] ******/ +SET QUOTED_IDENTIFIER ON; + +CREATE TABLE [#__contentitem_tag_map]( + [type_alias] [nvarchar](255) NOT NULL DEFAULT '', + [core_content_id] [bigint] NOT NULL, + [content_item_id] [int] NOT NULL, + [tag_id] [bigint] NOT NULL, + [tag_date] [datetime] NOT NULL DEFAULT '1900-01-01T00:00:00.000', + CONSTRAINT [#__contentitem_tag_map$uc_ItemnameTagid] UNIQUE NONCLUSTERED +( + [type_alias] ASC, + [content_item_id] ASC, + [tag_id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY]; + +CREATE NONCLUSTERED INDEX [idx_tag_name] ON [#__contentitem_tag_map] +( + [tag_id] ASC, + [type_alias] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_date_id] ON [#__contentitem_tag_map] +( + [tag_date] ASC, + [tag_id] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_tag] ON [#__contentitem_tag_map] +( + [tag_id] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_core_content_id] ON [#__contentitem_tag_map] +( + [core_content_id] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + + +/****** Object: Table [#__tags] ******/ +SET QUOTED_IDENTIFIER ON; + +CREATE TABLE [#__tags]( + [id] [int] IDENTITY(1,1) NOT NULL , + [parent_id] [bigint] NOT NULL DEFAULT '0', + [lft] [int] NOT NULL DEFAULT '0', + [rgt] [int] NOT NULL DEFAULT '0', + [level] [bigint] NOT NULL DEFAULT '0', + [path] [nvarchar](255) NOT NULL DEFAULT '', + [title] [nvarchar](255) NOT NULL, + [alias] [nvarchar](255) NOT NULL DEFAULT '', + [note] [nvarchar](255) NOT NULL DEFAULT '', + [description] [nvarchar](max) NOT NULL, + [published] [smallint] NOT NULL DEFAULT '0', + [checked_out] [bigint] NOT NULL DEFAULT '0', + [checked_out_time] [datetime] NOT NULL DEFAULT '1900-01-01T00:00:00.000', + [access] [int] NOT NULL DEFAULT '0', + [params] [nvarchar](max) NOT NULL, + [metadesc] [nvarchar](1024) NOT NULL, + [metakey] [nvarchar](1024) NOT NULL, + [metadata] [nvarchar](2048) NOT NULL, + [created_user_id] [bigint] NOT NULL DEFAULT '0', + [created_time] [datetime] NOT NULL DEFAULT '1900-01-01T00:00:00.000', + [created_by_alias] [nvarchar](255) NOT NULL DEFAULT '', + [modified_user_id] [bigint] NOT NULL DEFAULT '0', + [modified_time] [datetime] NOT NULL DEFAULT '1900-01-01T00:00:00.000', + [images] [nvarchar](max) NOT NULL, + [urls] [nvarchar](max) NOT NULL, + [hits] [bigint] NOT NULL DEFAULT '0', + [language] [nvarchar](7) NOT NULL, + [version] [bigint] NOT NULL DEFAULT '1', + [publish_up] [datetime] NOT NULL DEFAULT '1900-01-01T00:00:00.000', + [publish_down] [datetime] NOT NULL DEFAULT '1900-01-01T00:00:00.000', + CONSTRAINT [PK_#__tags_id] PRIMARY KEY CLUSTERED + ( + [id] ASC + )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY]; + +CREATE NONCLUSTERED INDEX [tag_idx] ON [#__tags] +( + [published] ASC, + [access] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_access] ON [#__tags] +( + [access] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_checkout] ON [#__tags] +( + [checked_out] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_path] ON [#__tags] +( + [path] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_left_right] ON [#__tags] +( + [lft] ASC, + [rgt] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_alias] ON [#__tags] +( + [alias] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_language] ON [#__tags] +( + [language] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +SET IDENTITY_INSERT #__tags ON; + +INSERT INTO #__tags (id,parent_id,lft,rgt,level,path,title,alias,note,description,published,checked_out,checked_out_time,access,params,metadesc,metakey,metadata,created_user_id,created_time,modified_user_id,modified_time,images,urls,hits,language) + SELECT 1,0,0,1,0,'','ROOT','root','','',1,0,'1900-01-01 00:00:00',1,'{}','','','',0,'2009-10-18 16:07:09',0,'1900-01-01 00:00:00','','',0,'*'; + +SET IDENTITY_INSERT #__tags OFF; + +/****** Object: Table [#__ucm_base] ******/ +SET QUOTED_IDENTIFIER ON; + +CREATE TABLE [#__ucm_base]( + [ucm_id] [bigint] IDENTITY(1,1) NOT NULL, + [ucm_item_id] [bigint] NOT NULL, + [ucm_type_id] [bigint] NOT NULL, + [ucm_language_id] [bigint] NOT NULL, + CONSTRAINT [PK_#__ucm_base_ucm_id] PRIMARY KEY CLUSTERED + ( + [ucm_id] ASC + )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY], +) ON [PRIMARY]; + +CREATE NONCLUSTERED INDEX [ucm_item_id] ON [#__ucm_base] +( + [ucm_item_id] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [ucm_type_id] ON [#__ucm_base] +( + [ucm_type_id] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [ucm_language_id] ON [#__ucm_base] +( + [ucm_language_id] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +/****** Object: Table [#__ucm_content] ******/ +SET QUOTED_IDENTIFIER ON; + +CREATE TABLE [#__ucm_content]( + [core_content_id] [bigint] IDENTITY(1,1) NOT NULL, + [core_type_alias] [nvarchar](255) NOT NULL, + [core_title] [nvarchar](255) NOT NULL DEFAULT '', + [core_alias] [nvarchar](255) NOT NULL DEFAULT '', + [core_body] [nvarchar](max) NOT NULL, + [core_state] [smallint] NOT NULL DEFAULT '0', + [core_checked_out_time] [datetime] NOT NULL DEFAULT '1900-01-01T00:00:00.000', + [core_checked_out_user_id] [bigint] NOT NULL DEFAULT '0', + [core_access] [bigint] NOT NULL DEFAULT '0', + [core_params] [nvarchar](max) NOT NULL, + [core_featured] [tinyint] NOT NULL DEFAULT '0', + [core_metadata] [nvarchar](max) NOT NULL, + [core_created_user_id] [bigint] NOT NULL DEFAULT '0', + [core_created_by_alias] [nvarchar](255) NOT NULL DEFAULT '', + [core_created_time] [datetime] NOT NULL DEFAULT '1900-01-01T00:00:00.000', + [core_modified_user_id] [bigint] NOT NULL DEFAULT '0', + [core_modified_time] [datetime] NOT NULL DEFAULT '1900-01-01T00:00:00.000', + [core_language] [nvarchar](7) NOT NULL, + [core_publish_up] [datetime] NOT NULL DEFAULT '1900-01-01T00:00:00.000', + [core_publish_down] [datetime] NOT NULL DEFAULT '1900-01-01T00:00:00.000', + [core_content_item_id] [bigint] NOT NULL DEFAULT '0', + [asset_id] [bigint] NOT NULL DEFAULT '0', + [core_images] [nvarchar](max) NOT NULL, + [core_urls] [nvarchar](max) NOT NULL, + [core_hits] [bigint] NOT NULL DEFAULT '0', + [core_version] [bigint] NOT NULL DEFAULT '1', + [core_ordering] [int] NOT NULL DEFAULT '0', + [core_metakey] [nvarchar](max) NOT NULL, + [core_metadesc] [nvarchar](max) NOT NULL, + [core_catid] [bigint] NOT NULL DEFAULT '0', + [core_xreference] [nvarchar](50) NOT NULL, + [core_type_id] [bigint] NOT NULL DEFAULT '0', + CONSTRAINT [PK_#__ucm_content_core_content_id] PRIMARY KEY CLUSTERED + ( + [core_content_id] ASC + )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY], + CONSTRAINT [#__ucm_content_core_content_id$idx_type_alias_item_id] UNIQUE NONCLUSTERED + ( + [core_type_alias] ASC, + [core_content_item_id] ASC + )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY]; + +CREATE NONCLUSTERED INDEX [tag_idx] ON [#__ucm_content] +( + [core_state] ASC, + [core_access] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_access] ON [#__ucm_content] +( + [core_access] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_alias] ON [#__ucm_content] +( + [core_alias] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_language] ON [#__ucm_content] +( + [core_language] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_title] ON [#__ucm_content] +( + [core_title] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_modified_time] ON [#__ucm_content] +( + [core_modified_time] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_created_time] ON [#__ucm_content] +( + [core_created_time] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_content_type] ON [#__ucm_content] +( + [core_type_alias] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_core_modified_user_id] ON [#__ucm_content] +( + [core_modified_user_id] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_core_checked_out_user_id] ON [#__ucm_content] +( + [core_checked_out_user_id] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_core_created_user_id] ON [#__ucm_content] +( + [core_created_user_id] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + +CREATE NONCLUSTERED INDEX [idx_core_type_id] ON [#__ucm_content] +( + [core_type_id] ASC +)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF); + + +SET IDENTITY_INSERT #__extensions ON; + +INSERT INTO #__extensions (extension_id, name, type, element, folder, client_id, enabled, access, protected, manifest_cache, params, custom_data, system_data, checked_out, checked_out_time, ordering, state) + SELECT 29, 'com_tags', 'component', 'com_tags', '', 1, 1, 1, 1, '{"name":"com_joomlaupdate","type":"component","creationDate":"March 2013","author":"Joomla! Project","copyright":"(C) 2005 - 2013 Open Source Matters. All rights reserved.","authorEmail":"admin@joomla.org","authorUrl":"www.joomla.org","version":"3.1.0","description":"COM_TAGS_XML_DESCRIPTION","group":""}', '{}', '', '', 0, '1900-01-01 00:00:00', 0, 0; + +SET IDENTITY_INSERT #__extensions OFF; + +SET IDENTITY_INSERT #__menu ON; + +INSERT INTO #__menu (id, menutype, title, alias, note, path, link, type, published, parent_id, level, component_id, ordering, checked_out, checked_out_time, browserNav, access, img, template_style_id, params, lft, rgt, home, language, client_id) + SELECT 23, 'menu', 'com_tags', 'Tags', '', 'Tags', 'index.php?option=com_tags', 'component', 0, 1, 1, 29, 0, '1900-01-01 00:00:00', 0, 0, 'class:tags', 0, '', 43, 44, 0, '*', 1 + +SET IDENTITY_INSERT #__menu OFF; diff --git a/administrator/components/com_admin/sql/updates/sqlazure/3.1.1.sql b/administrator/components/com_admin/sql/updates/sqlazure/3.1.1.sql new file mode 100644 index 0000000..df442fa --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/3.1.1.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.1.1 \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/sqlazure/3.1.2.sql b/administrator/components/com_admin/sql/updates/sqlazure/3.1.2.sql new file mode 100644 index 0000000..0b39c5b --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/3.1.2.sql @@ -0,0 +1,11 @@ +UPDATE [#__content_types] SET [table] = '{"special":{"dbtable":"#__content","key":"id","type":"Content","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE [type_title] = 'Article';UPDATE [#__content_types] SET [table] = '{"special":{"dbtable":"#__weblinks","key":"id","type":"Weblink","prefix":"WeblinksTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE [type_title] = 'Weblink';UPDATE [#__content_types] SET [table] = '{"special":{"dbtable":"#__contact_details","key":"id","type":"Contact","prefix":"ContactTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE [type_title] = 'Contact';UPDATE [#__content_types] SET [table] = '{"special":{"dbtable":"#__newsfeeds","key":"id","type":"Newsfeed","prefix":"NewsfeedsTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE [type_title] = 'Newsfeed';UPDATE [#__content_types] SET [table] = '{"special":{"dbtable":"#__users","key":"id","type":"User","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE [type_title] = 'User';UPDATE [#__content_types] SET [table] = '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE [type_title] = 'Article Category';UPDATE [#__content_types] SET [table] = '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE [type_title] = 'Contact Category';UPDATE [#__content_types] SET [table] = '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE [type_title] = 'Newsfeeds Category';UPDATE [#__content_types] SET [table] = '{"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE [type_title] = 'Weblinks Category';UPDATE [#__content_types] SET [table] = '{"special":{"dbtable":"#__tags","key":"tag_id","type":"Tag","prefix":"TagsTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' WHERE [type_title] = 'Tag'; +UPDATE [#__content_types] SET [field_mappings] = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"introtext", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"attribs", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"asset_id"}, "special": {"fulltext":"fulltext"}}' WHERE [type_id] = '1'; +UPDATE [#__content_types] SET [field_mappings] = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"description", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"url", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}, "special": {}}' WHERE [type_id] = '2'; +UPDATE [#__content_types] SET [field_mappings] = '{"common":{"core_content_item_id":"id","core_title":"name","core_state":"published","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"address", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"image", "core_urls":"webpage", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}, "special": {"con_position":"con_position","suburb":"suburb","state":"state","country":"country","postcode":"postcode","telephone":"telephone","fax":"fax","misc":"misc","email_to":"email_to","default_con":"default_con","user_id":"user_id","mobile":"mobile","sortname1":"sortname1","sortname2":"sortname2","sortname3":"sortname3"}}' WHERE [type_id] = '3'; +UPDATE [#__content_types] SET [field_mappings] = '{"common":{"core_content_item_id":"id","core_title":"name","core_state":"published","core_alias":"alias","core_created_time":"created","core_modified_time":"modified","core_body":"description", "core_hits":"hits","core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"link", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}, "special": {"numarticles":"numarticles","cache_time":"cache_time","rtl":"rtl"}}' WHERE [type_id] = '4'; +UPDATE [#__content_types] SET [field_mappings] = '{"common":{"core_content_item_id":"id","core_title":"name","core_state":"null","core_alias":"username","core_created_time":"registerdate","core_modified_time":"lastvisitDate","core_body":"null", "core_hits":"null","core_publish_up":"null","core_publish_down":"null","access":"null", "core_params":"params", "core_featured":"null", "core_metadata":"null", "core_language":"null", "core_images":"null", "core_urls":"null", "core_version":"null", "core_ordering":"null", "core_metakey":"null", "core_metadesc":"null", "core_catid":"null", "core_xreference":"null", "asset_id":"null"}, "special": {}}' WHERE [type_id] = '5'; +UPDATE [#__content_types] SET [field_mappings] = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}' WHERE [type_id] = '6'; +UPDATE [#__content_types] SET [field_mappings] = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}' WHERE [type_id] = '7'; +UPDATE [#__content_types] SET [field_mappings] = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}' WHERE [type_id] = '8'; +UPDATE [#__content_types] SET [field_mappings] = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}' WHERE [type_id] = '9'; +UPDATE [#__content_types] SET [field_mappings] = '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"urls", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"null", "core_xreference":"null", "asset_id":"null"}, "special": {"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path"}}' WHERE [type_id] = '10'; diff --git a/administrator/components/com_admin/sql/updates/sqlazure/3.1.3.sql b/administrator/components/com_admin/sql/updates/sqlazure/3.1.3.sql new file mode 100644 index 0000000..ebc1102 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/3.1.3.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.1.3 diff --git a/administrator/components/com_admin/sql/updates/sqlazure/3.1.4.sql b/administrator/components/com_admin/sql/updates/sqlazure/3.1.4.sql new file mode 100644 index 0000000..4f58888 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/3.1.4.sql @@ -0,0 +1,6 @@ +SET IDENTITY_INSERT #__extensions ON; + +INSERT INTO #__extensions (extension_id, name, type, element, folder, client_id, enabled, access, protected, manifest_cache, params, custom_data, system_data, checked_out, checked_out_time, ordering, state) +SELECT 104, 'IDNA Convert', 'library', 'idna_convert', '', 0, 1, 1, 1, '', '', '', '', 0, '1900-01-01 00:00:00', 0, 0; + +SET IDENTITY_INSERT #__extensions OFF; diff --git a/administrator/components/com_admin/sql/updates/sqlazure/3.1.5.sql b/administrator/components/com_admin/sql/updates/sqlazure/3.1.5.sql new file mode 100644 index 0000000..2c9caba --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/3.1.5.sql @@ -0,0 +1 @@ +# Placeholder file for database changes for version 3.1.5 diff --git a/administrator/components/com_admin/sql/updates/sqlazure/index.html b/administrator/components/com_admin/sql/updates/sqlazure/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/views/help/index.html b/administrator/components/com_admin/views/help/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/views/help/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/views/help/tmpl/default.php b/administrator/components/com_admin/views/help/tmpl/default.php new file mode 100644 index 0000000..12a92a3 --- /dev/null +++ b/administrator/components/com_admin/views/help/tmpl/default.php @@ -0,0 +1,50 @@ + +
+
+ +
+ +
+
+ +
diff --git a/administrator/components/com_admin/views/help/tmpl/index.html b/administrator/components/com_admin/views/help/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/views/help/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/views/help/view.html.php b/administrator/components/com_admin/views/help/view.html.php new file mode 100644 index 0000000..7709c01 --- /dev/null +++ b/administrator/components/com_admin/views/help/view.html.php @@ -0,0 +1,74 @@ +help_search = $this->get('HelpSearch'); + $this->page = $this->get('Page'); + $this->toc = $this->get('Toc'); + $this->lang_tag = $this->get('LangTag'); + $this->latest_version_check = $this->get('LatestVersionCheck'); + + $this->addToolbar(); + parent::display($tpl); + } + /** + * Setup the Toolbar + * + * @since 1.6 + */ + protected function addToolbar() + { + JToolbarHelper::title(JText::_('COM_ADMIN_HELP'), 'help_header.png'); + } +} diff --git a/administrator/components/com_admin/views/index.html b/administrator/components/com_admin/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/views/profile/index.html b/administrator/components/com_admin/views/profile/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/views/profile/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/views/profile/tmpl/edit.php b/administrator/components/com_admin/views/profile/tmpl/edit.php new file mode 100644 index 0000000..afe7d95 --- /dev/null +++ b/administrator/components/com_admin/views/profile/tmpl/edit.php @@ -0,0 +1,71 @@ +form->getFieldsets(); +?> + + + +
+ 'account')); ?> + + + form->getFieldset('user_details') as $field) : ?> +
+
label; ?>
+
input; ?>
+
+ + + + name == 'user_details') : + continue; + endif; + ?> + name, JText::_($fieldset->label, true)); ?> + form->getFieldset($fieldset->name) as $field) : ?> + hidden) : ?> +
+
input; ?>
+
+ +
+
label; ?>
+
input; ?>
+
+ + + + + + + + +
diff --git a/administrator/components/com_admin/views/profile/tmpl/index.html b/administrator/components/com_admin/views/profile/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/views/profile/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/views/profile/view.html.php b/administrator/components/com_admin/views/profile/view.html.php new file mode 100644 index 0000000..c9e7cb1 --- /dev/null +++ b/administrator/components/com_admin/views/profile/view.html.php @@ -0,0 +1,66 @@ +form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->form->setValue('password', null); + $this->form->setValue('password2', null); + + parent::display($tpl); + $this->addToolbar(); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + JFactory::getApplication()->input->set('hidemainmenu', 1); + + JToolbarHelper::title(JText::_('COM_ADMIN_VIEW_PROFILE_TITLE'), 'user-profile'); + JToolbarHelper::apply('profile.apply'); + JToolbarHelper::save('profile.save'); + JToolbarHelper::cancel('profile.cancel', 'JTOOLBAR_CLOSE'); + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_ADMIN_USER_PROFILE_EDIT'); + } +} diff --git a/administrator/components/com_admin/views/sysinfo/index.html b/administrator/components/com_admin/views/sysinfo/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/views/sysinfo/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/views/sysinfo/tmpl/default.php b/administrator/components/com_admin/views/sysinfo/tmpl/default.php new file mode 100644 index 0000000..146a90a --- /dev/null +++ b/administrator/components/com_admin/views/sysinfo/tmpl/default.php @@ -0,0 +1,46 @@ + + +
+
+ +
+ 'site')); ?> + + + loadTemplate('system'); ?> + + + + loadTemplate('phpsettings'); ?> + + + + loadTemplate('config'); ?> + + + + loadTemplate('directory'); ?> + + + + loadTemplate('phpinfo'); ?> + + + +
+ +
+
diff --git a/administrator/components/com_admin/views/sysinfo/tmpl/default_config.php b/administrator/components/com_admin/views/sysinfo/tmpl/default_config.php new file mode 100644 index 0000000..e34f80b --- /dev/null +++ b/administrator/components/com_admin/views/sysinfo/tmpl/default_config.php @@ -0,0 +1,43 @@ + +
+ + + + + + + + + + + + + + + config as $key => $value):?> + + + + + + +
+ + + +
 
+ + + +
+
diff --git a/administrator/components/com_admin/views/sysinfo/tmpl/default_directory.php b/administrator/components/com_admin/views/sysinfo/tmpl/default_directory.php new file mode 100644 index 0000000..fecaac5 --- /dev/null +++ b/administrator/components/com_admin/views/sysinfo/tmpl/default_directory.php @@ -0,0 +1,43 @@ + +
+ + + + + + + + + + + + + + + directory as $dir => $info) : ?> + + + + + + +
+ + + +
 
+ + + +
+
diff --git a/administrator/components/com_admin/views/sysinfo/tmpl/default_phpinfo.php b/administrator/components/com_admin/views/sysinfo/tmpl/default_phpinfo.php new file mode 100644 index 0000000..5a7a07b --- /dev/null +++ b/administrator/components/com_admin/views/sysinfo/tmpl/default_phpinfo.php @@ -0,0 +1,15 @@ + +
+ + php_info;?> +
diff --git a/administrator/components/com_admin/views/sysinfo/tmpl/default_phpsettings.php b/administrator/components/com_admin/views/sysinfo/tmpl/default_phpsettings.php new file mode 100644 index 0000000..6faa4af --- /dev/null +++ b/administrator/components/com_admin/views/sysinfo/tmpl/default_phpsettings.php @@ -0,0 +1,162 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
  +
+ + + php_settings['safe_mode']); ?> +
+ + + php_settings['open_basedir']); ?> +
+ + + php_settings['display_errors']); ?> +
+ + + php_settings['short_open_tag']); ?> +
+ + + php_settings['file_uploads']); ?> +
+ + + php_settings['magic_quotes_gpc']); ?> +
+ + + php_settings['register_globals']); ?> +
+ + + php_settings['output_buffering']); ?> +
+ + + php_settings['session.save_path']); ?> +
+ + + php_settings['session.auto_start']); ?> +
+ + + php_settings['xml']); ?> +
+ + + php_settings['zlib']); ?> +
+ + + php_settings['zip']); ?> +
+ + + php_settings['disable_functions']); ?> +
+ + + php_settings['mbstring']); ?> +
+ + + php_settings['iconv']); ?> +
+
diff --git a/administrator/components/com_admin/views/sysinfo/tmpl/default_system.php b/administrator/components/com_admin/views/sysinfo/tmpl/default_system.php new file mode 100644 index 0000000..6845f73 --- /dev/null +++ b/administrator/components/com_admin/views/sysinfo/tmpl/default_system.php @@ -0,0 +1,105 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
 
+ + + info['php'];?> +
+ + + info['dbversion'];?> +
+ + + info['dbcollation'];?> +
+ + + info['phpversion'];?> +
+ + + info['server']); ?> +
+ + + info['sapi_name'];?> +
+ + + info['version'];?> +
+ + + info['platform'];?> +
+ + + info['useragent']);?> +
+
diff --git a/administrator/components/com_admin/views/sysinfo/tmpl/index.html b/administrator/components/com_admin/views/sysinfo/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_admin/views/sysinfo/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_admin/views/sysinfo/view.html.php b/administrator/components/com_admin/views/sysinfo/view.html.php new file mode 100644 index 0000000..487e65f --- /dev/null +++ b/administrator/components/com_admin/views/sysinfo/view.html.php @@ -0,0 +1,99 @@ +authorise('core.admin')) + { + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); + } + + $this->php_settings = $this->get('PhpSettings'); + $this->config = $this->get('config'); + $this->info = $this->get('info'); + $this->php_info = $this->get('PhpInfo'); + $this->directory = $this->get('directory'); + + $this->addToolbar(); + $this->_setSubMenu(); + parent::display($tpl); + } + + /** + * Setup the SubMenu + * + * @return void + * + * @since 1.6 + * @note Necessary for Hathor compatibility + */ + protected function _setSubMenu() + { + try + { + $contents = $this->loadTemplate('navigation'); + $document = JFactory::getDocument(); + $document->setBuffer($contents, 'modules', 'submenu'); + } + catch (Exception $e) + { + } + } + + /** + * Setup the Toolbar + * + * @since 1.6 + */ + protected function addToolbar() + { + JToolbarHelper::title(JText::_('COM_ADMIN_SYSTEM_INFORMATION'), 'systeminfo.png'); + JToolbarHelper::help('JHELP_SITE_SYSTEM_INFORMATION'); + } +} diff --git a/administrator/components/com_banners/access.xml b/administrator/components/com_banners/access.xml new file mode 100644 index 0000000..0a8b8b3 --- /dev/null +++ b/administrator/components/com_banners/access.xml @@ -0,0 +1,17 @@ + + +
+ + + + + + +
+
+ + + + +
+
diff --git a/administrator/components/com_banners/banners.php b/administrator/components/com_banners/banners.php new file mode 100644 index 0000000..3febd61 --- /dev/null +++ b/administrator/components/com_banners/banners.php @@ -0,0 +1,20 @@ +authorise('core.manage', 'com_banners')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +// Execute the task. +$controller = JControllerLegacy::getInstance('Banners'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_banners/banners.xml b/administrator/components/com_banners/banners.xml new file mode 100644 index 0000000..b504f02 --- /dev/null +++ b/administrator/components/com_banners/banners.xml @@ -0,0 +1,68 @@ + + + com_banners + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + + GNU General Public License version 2 or later; see + LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_BANNERS_XML_DESCRIPTION + + + + sql/install.mysql.utf8.sql + + + + + sql/uninstall.mysql.utf8.sql + + + + + banners.php + controller.php + index.html + router.php + helpers + models + + + com_banners + + + com_banners_banners + com_banners_categories + com_banners_clients + com_banners_tracks + + + access.xml + banners.php + config.xml + controller.php + index.html + controllers + helpers + models + tables + views + + + language/en-GB.com_banners.ini + language/en-GB.com_banners.sys.ini + + + + diff --git a/administrator/components/com_banners/config.xml b/administrator/components/com_banners/config.xml new file mode 100644 index 0000000..37e7cc9 --- /dev/null +++ b/administrator/components/com_banners/config.xml @@ -0,0 +1,76 @@ + + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+
diff --git a/administrator/components/com_banners/controller.php b/administrator/components/com_banners/controller.php new file mode 100644 index 0000000..3e44254 --- /dev/null +++ b/administrator/components/com_banners/controller.php @@ -0,0 +1,63 @@ +input->get('view', 'banners'); + $layout = $this->input->get('layout', 'default'); + $id = $this->input->getInt('id'); + + // Check for edit form. + if ($view == 'banner' && $layout == 'edit' && !$this->checkEditId('com_banners.edit.banner', $id)) { + + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_banners&view=banners', false)); + + return false; + } + elseif ($view == 'client' && $layout == 'edit' && !$this->checkEditId('com_banners.edit.client', $id)) { + + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_banners&view=clients', false)); + + return false; + } + + parent::display(); + + return $this; + } +} diff --git a/administrator/components/com_banners/controllers/banner.php b/administrator/components/com_banners/controllers/banner.php new file mode 100644 index 0000000..db20c8b --- /dev/null +++ b/administrator/components/com_banners/controllers/banner.php @@ -0,0 +1,115 @@ +input->getInt('filter_category_id'); + $categoryId = JArrayHelper::getValue($data, 'catid', $filter, 'int'); + $allow = null; + + if ($categoryId) + { + // If the category has been passed in the URL check it. + $allow = $user->authorise('core.create', $this->option . '.category.' . $categoryId); + } + + if ($allow === null) + { + // In the absence of better information, revert to the component permissions. + return parent::allowAdd($data); + } + else + { + return $allow; + } + } + + /** + * Method override to check if you can edit an existing record. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowEdit($data = array(), $key = 'id') + { + $user = JFactory::getUser(); + $recordId = (int) isset($data[$key]) ? $data[$key] : 0; + $categoryId = 0; + + if ($recordId) + { + $categoryId = (int) $this->getModel()->getItem($recordId)->catid; + } + + if ($categoryId) + { + // The category has been set. Check the category permissions. + return $user->authorise('core.edit', $this->option . '.category.' . $categoryId); + } + else + { + // Since there is no asset tracking, revert to the component permissions. + return parent::allowEdit($data, $key); + } + } + + /** + * Method to run batch operations. + * + * @param string $model The model + * + * @return boolean True on success. + * + * @since 2.5 + */ + public function batch($model = null) + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Set the model + $model = $this->getModel('Banner', '', array()); + + // Preset the redirect + $this->setRedirect(JRoute::_('index.php?option=com_banners&view=banners' . $this->getRedirectToListAppend(), false)); + + return parent::batch($model); + } + +} diff --git a/administrator/components/com_banners/controllers/banners.php b/administrator/components/com_banners/controllers/banners.php new file mode 100644 index 0000000..6706a1a --- /dev/null +++ b/administrator/components/com_banners/controllers/banners.php @@ -0,0 +1,90 @@ +registerTask('sticky_unpublish', 'sticky_publish'); + } + + /** + * Proxy for getModel. + * @since 1.6 + */ + public function getModel($name = 'Banner', $prefix = 'BannersModel', $config = array('ignore_request' => true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } + + /** + * @since 1.6 + */ + public function sticky_publish() + { + // Check for request forgeries. + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $ids = $this->input->get('cid', array(), 'array'); + $values = array('sticky_publish' => 1, 'sticky_unpublish' => 0); + $task = $this->getTask(); + $value = JArrayHelper::getValue($values, $task, 0, 'int'); + + if (empty($ids)) + { + JError::raiseWarning(500, JText::_('COM_BANNERS_NO_BANNERS_SELECTED')); + } + else + { + // Get the model. + $model = $this->getModel(); + + // Change the state of the records. + if (!$model->stick($ids, $value)) + { + JError::raiseWarning(500, $model->getError()); + } else { + if ($value == 1) + { + $ntext = 'COM_BANNERS_N_BANNERS_STUCK'; + } else { + $ntext = 'COM_BANNERS_N_BANNERS_UNSTUCK'; + } + $this->setMessage(JText::plural($ntext, count($ids))); + } + } + + $this->setRedirect('index.php?option=com_banners&view=banners'); + } +} diff --git a/administrator/components/com_banners/controllers/client.php b/administrator/components/com_banners/controllers/client.php new file mode 100644 index 0000000..e2821f0 --- /dev/null +++ b/administrator/components/com_banners/controllers/client.php @@ -0,0 +1,26 @@ + true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } +} diff --git a/administrator/components/com_banners/controllers/index.html b/administrator/components/com_banners/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/controllers/tracks.php b/administrator/components/com_banners/controllers/tracks.php new file mode 100644 index 0000000..09b86e2 --- /dev/null +++ b/administrator/components/com_banners/controllers/tracks.php @@ -0,0 +1,92 @@ + true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } + + /** + * Method to remove a record. + * + * @return void + * @since 1.6 + */ + public function delete() + { + // Check for request forgeries. + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Get the model. + $model = $this->getModel(); + + // Load the filter state. + $app = JFactory::getApplication(); + + $type = $app->getUserState($this->context.'.filter.type'); + $model->setState('filter.type', $type); + + $begin = $app->getUserState($this->context.'.filter.begin'); + $model->setState('filter.begin', $begin); + + $end = $app->getUserState($this->context.'.filter.end'); + $model->setState('filter.end', $end); + + $categoryId = $app->getUserState($this->context.'.filter.category_id'); + $model->setState('filter.category_id', $categoryId); + + $clientId = $app->getUserState($this->context.'.filter.client_id'); + $model->setState('filter.client_id', $clientId); + + $model->setState('list.limit', 0); + $model->setState('list.start', 0); + + $count = $model->getTotal(); + // Remove the items. + if (!$model->delete()) + { + JError::raiseWarning(500, $model->getError()); + } + else + { + $this->setMessage(JText::plural('COM_BANNERS_TRACKS_N_ITEMS_DELETED', $count)); + } + + $this->setRedirect('index.php?option=com_banners&view=tracks'); + } +} diff --git a/administrator/components/com_banners/controllers/tracks.raw.php b/administrator/components/com_banners/controllers/tracks.raw.php new file mode 100644 index 0000000..90b4257 --- /dev/null +++ b/administrator/components/com_banners/controllers/tracks.raw.php @@ -0,0 +1,106 @@ + true)); + return $model; + } + + /** + * Display method for the raw track data. + * + * @param boolean If true, the view output will be cached + * @param array An array of safe url parameters and their variable types, for valid values see {@link JFilterInput::clean()}. + * + * @return JController This object to support chaining. + * @since 1.5 + * @todo This should be done as a view, not here! + */ + public function display($cachable = false, $urlparams = false) + { + // Get the document object. + $document = JFactory::getDocument(); + $vName = 'tracks'; + $vFormat = 'raw'; + + // Get and render the view. + if ($view = $this->getView($vName, $vFormat)) + { + // Get the model for the view. + $model = $this->getModel($vName); + + // Load the filter state. + $app = JFactory::getApplication(); + + $type = $app->getUserState($this->context.'.filter.type'); + $model->setState('filter.type', $type); + + $begin = $app->getUserState($this->context.'.filter.begin'); + $model->setState('filter.begin', $begin); + + $end = $app->getUserState($this->context.'.filter.end'); + $model->setState('filter.end', $end); + + $categoryId = $app->getUserState($this->context.'.filter.category_id'); + $model->setState('filter.category_id', $categoryId); + + $clientId = $app->getUserState($this->context.'.filter.client_id'); + $model->setState('filter.client_id', $clientId); + + $model->setState('list.limit', 0); + $model->setState('list.start', 0); + + $form = JRequest::getVar('jform'); + $model->setState('basename', $form['basename']); + $model->setState('compressed', $form['compressed']); + + $config = JFactory::getConfig(); + $cookie_domain = $config->get('cookie_domain', ''); + $cookie_path = $config->get('cookie_path', '/'); + + setcookie(JApplication::getHash($this->context.'.basename'), $form['basename'], time() + 365 * 86400, $cookie_path, $cookie_domain); + setcookie(JApplication::getHash($this->context.'.compressed'), $form['compressed'], time() + 365 * 86400, $cookie_path, $cookie_domain); + + // Push the model into the view (as default). + $view->setModel($model, true); + + // Push document object into the view. + $view->document = $document; + + $view->display(); + } + } +} diff --git a/administrator/components/com_banners/helpers/banners.php b/administrator/components/com_banners/helpers/banners.php new file mode 100644 index 0000000..aa3b2ab --- /dev/null +++ b/administrator/components/com_banners/helpers/banners.php @@ -0,0 +1,218 @@ +set($action->name, $user->authorise($action->name, $assetName)); + } + + return $result; + } + + /** + * @return boolean + * @since 1.6 + */ + public static function updateReset() + { + $user = JFactory::getUser(); + $db = JFactory::getDbo(); + $nullDate = $db->getNullDate(); + $now = JFactory::getDate(); + $query = $db->getQuery(true) + ->select('*') + ->from('#__banners') + ->where($db->quote($now) . ' >= ' . $db->quote('reset')) + ->where($db->quoteName('reset') . ' != ' . $db->quote($nullDate) . ' AND ' . $db->quoteName('reset') . '!=NULL') + ->where('(' . $db->quoteName('checked_out') . ' = 0 OR ' . $db->quoteName('checked_out') . ' = ' . (int) $db->quote($user->id) . ')'); + $db->setQuery($query); + + try + { + $rows = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + return false; + } + + JTable::addIncludePath(JPATH_COMPONENT_ADMINISTRATOR . '/tables'); + + foreach ($rows as $row) + { + $purchase_type = $row->purchase_type; + + if ($purchase_type < 0 && $row->cid) + { + $client = JTable::getInstance('Client', 'BannersTable'); + $client->load($row->cid); + $purchase_type = $client->purchase_type; + } + + if ($purchase_type < 0) + { + $params = JComponentHelper::getParams('com_banners'); + $purchase_type = $params->get('purchase_type'); + } + + switch($purchase_type) + { + case 1: + $reset = $nullDate; + break; + case 2: + $date = JFactory::getDate('+1 year '.date('Y-m-d', strtotime('now'))); + $reset = $db->quote($date->toSql()); + break; + case 3: + $date = JFactory::getDate('+1 month '.date('Y-m-d', strtotime('now'))); + $reset = $db->quote($date->toSql()); + break; + case 4: + $date = JFactory::getDate('+7 day '.date('Y-m-d', strtotime('now'))); + $reset = $db->quote($date->toSql()); + break; + case 5: + $date = JFactory::getDate('+1 day '.date('Y-m-d', strtotime('now'))); + $reset = $db->quote($date->toSql()); + break; + } + + // Update the row ordering field. + $query->clear() + ->update($db->quoteName('#__banners')) + ->set($db->quoteName('reset') . ' = ' . $db->quote($reset)) + ->set($db->quoteName('impmade') . ' = ' . $db->quote(0)) + ->set($db->quoteName('clicks') . ' = ' . $db->quote(0)) + ->where($db->quoteName('id') . ' = ' . $db->quote($row->id)); + $db->setQuery($query); + + try + { + $db->execute(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $db->getMessage()); + return false; + } + } + + return true; + } + + public static function getClientOptions() + { + $options = array(); + + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('id As value, name As text') + ->from('#__banner_clients AS a') + ->order('a.name'); + + // Get the options. + $db->setQuery($query); + + try + { + $options = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + } + + // Merge any additional options in the XML definition. + //$options = array_merge(parent::getOptions(), $options); + + array_unshift($options, JHtml::_('select.option', '0', JText::_('COM_BANNERS_NO_CLIENT'))); + + return $options; + } +} diff --git a/administrator/components/com_banners/helpers/html/banner.php b/administrator/components/com_banners/helpers/html/banner.php new file mode 100644 index 0000000..b4dafb6 --- /dev/null +++ b/administrator/components/com_banners/helpers/html/banner.php @@ -0,0 +1,116 @@ +', + JText::_('COM_BANNERS_BATCH_CLIENT_LABEL'), + '', + '' + ); + + return implode("\n", $lines); + } + + /** + * Method to get the field options. + * + * @return array The field option objects. + * @since 1.6 + */ + public static function clientlist() + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('id As value, name As text') + ->from('#__banner_clients AS a') + ->order('a.name'); + + // Get the options. + $db->setQuery($query); + + try + { + $options = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + } + + return $options; + } + + /** + * Returns a pinned state on a grid + * + * @param integer $value The state value. + * @param integer $i The row index + * @param boolean $enabled An optional setting for access control on the action. + * @param string $checkbox An optional prefix for checkboxes. + * + * @return string The Html code + * + * @see JHtmlJGrid::state + * + * @since 2.5.5 + */ + public static function pinned($value, $i, $enabled = true, $checkbox = 'cb') + { + $states = array( + 1 => array( + 'sticky_unpublish', + 'COM_BANNERS_BANNERS_PINNED', + 'COM_BANNERS_BANNERS_HTML_PIN_BANNER', + 'COM_BANNERS_BANNERS_PINNED', + true, + 'publish', + 'publish' + ), + 0 => array( + 'sticky_publish', + 'COM_BANNERS_BANNERS_UNPINNED', + 'COM_BANNERS_BANNERS_HTML_UNPIN_BANNER', + 'COM_BANNERS_BANNERS_UNPINNED', + true, + 'unpublish', + 'unpublish' + ), + ); + + return JHtml::_('jgrid.state', $states, $value, $i, 'banners.', $enabled, true, $checkbox); + } + +} diff --git a/administrator/components/com_banners/helpers/html/index.html b/administrator/components/com_banners/helpers/html/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/helpers/html/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/helpers/index.html b/administrator/components/com_banners/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/index.html b/administrator/components/com_banners/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/models/banner.php b/administrator/components/com_banners/models/banner.php new file mode 100644 index 0000000..d41e235 --- /dev/null +++ b/administrator/components/com_banners/models/banner.php @@ -0,0 +1,549 @@ +setError(JText::_('JGLOBAL_NO_ITEM_SELECTED')); + return false; + } + + $done = false; + + if (!empty($commands['category_id'])) + { + $cmd = JArrayHelper::getValue($commands, 'move_copy', 'c'); + + if ($cmd == 'c') + { + $result = $this->batchCopy($commands['category_id'], $pks, $contexts); + if (is_array($result)) + { + $pks = $result; + } + else + { + return false; + } + } + elseif ($cmd == 'm' && !$this->batchMove($commands['category_id'], $pks, $contexts)) + { + return false; + } + $done = true; + } + + if (strlen($commands['client_id']) > 0) + { + if (!$this->batchClient($commands['client_id'], $pks, $contexts)) + { + return false; + } + + $done = true; + } + + if (!empty($commands['language_id'])) + { + if (!$this->batchLanguage($commands['language_id'], $pks, $contexts)) + { + return false; + } + + $done = true; + } + + if (!$done) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_INSUFFICIENT_BATCH_INFORMATION')); + return false; + } + + // Clear the cache + $this->cleanCache(); + + return true; + } + + /** + * Batch client changes for a group of banners. + * + * @param string $value The new value matching a client. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 2.5 + */ + protected function batchClient($value, $pks, $contexts) + { + // Set the variables + $user = JFactory::getUser(); + $table = $this->getTable(); + + foreach ($pks as $pk) + { + if ($user->authorise('core.edit', $contexts[$pk])) + { + $table->reset(); + $table->load($pk); + $table->cid = (int) $value; + + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + } + else + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT')); + return false; + } + } + + // Clean the cache + $this->cleanCache(); + + return true; + } + + /** + * Batch copy items to a new category or current. + * + * @param integer $value The new category. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return mixed An array of new IDs on success, boolean false on failure. + * + * @since 2.5 + */ + protected function batchCopy($value, $pks, $contexts) + { + $categoryId = (int) $value; + + $table = $this->getTable(); + $i = 0; + + // Check that the category exists + if ($categoryId) + { + $categoryTable = JTable::getInstance('Category'); + if (!$categoryTable->load($categoryId)) + { + if ($error = $categoryTable->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND')); + return false; + } + } + } + + if (empty($categoryId)) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND')); + return false; + } + + // Check that the user has create permission for the component + $user = JFactory::getUser(); + if (!$user->authorise('core.create', 'com_banners.category.' . $categoryId)) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE')); + return false; + } + + // Parent exists so we let's proceed + while (!empty($pks)) + { + // Pop the first ID off the stack + $pk = array_shift($pks); + + $table->reset(); + + // Check that the row actually exists + if (!$table->load($pk)) + { + if ($error = $table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Not fatal error + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + } + + // Alter the title & alias + $data = $this->generateNewTitle($categoryId, $table->alias, $table->name); + $table->name = $data['0']; + $table->alias = $data['1']; + + // Reset the ID because we are making a copy + $table->id = 0; + + // New category ID + $table->catid = $categoryId; + + // TODO: Deal with ordering? + //$table->ordering = 1; + + // Check the row. + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // Store the row. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Get the new item ID + $newId = $table->get('id'); + + // Add the new ID to the array + $newIds[$i] = $newId; + $i++; + } + + // Clean the cache + $this->cleanCache(); + + return $newIds; + } + + /** + * Method to test whether a record can be deleted. + * + * @param object $record A record object. + * + * @return boolean True if allowed to delete the record. Defaults to the permission set in the component. + * + * @since 1.6 + */ + protected function canDelete($record) + { + if (!empty($record->id)) + { + if ($record->state != -2) + { + return; + } + $user = JFactory::getUser(); + + if (!empty($record->catid)) + { + return $user->authorise('core.delete', 'com_banners.category.' . (int) $record->catid); + } + else + { + return parent::canDelete($record); + } + } + } + + /** + * Method to test whether a record can have its state changed. + * + * @param object $record A record object. + * + * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. + * + * @since 1.6 + */ + protected function canEditState($record) + { + $user = JFactory::getUser(); + + // Check against the category. + if (!empty($record->catid)) + { + return $user->authorise('core.edit.state', 'com_banners.category.' . (int) $record->catid); + } + // Default to component settings if category not known. + else + { + return parent::canEditState($record); + } + } + + /** + * Returns a JTable object, always creating it. + * + * @param string $type The table type to instantiate. [optional] + * @param string $prefix A prefix for the table class name. [optional] + * @param array $config Configuration array for model. [optional] + * + * @return JTable A database object + * + * @since 1.6 + */ + public function getTable($type = 'Banner', $prefix = 'BannersTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Method to get the record form. + * + * @param array $data Data for the form. [optional] + * @param boolean $loadData True if the form is to load its own data (default case), false if not. [optional] + * + * @return mixed A JForm object on success, false on failure + * + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + // Get the form. + $form = $this->loadForm('com_banners.banner', 'banner', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + // Determine correct permissions to check. + if ($this->getState('banner.id')) + { + // Existing record. Can only edit in selected categories. + $form->setFieldAttribute('catid', 'action', 'core.edit'); + } + else + { + // New record. Can only create in selected categories. + $form->setFieldAttribute('catid', 'action', 'core.create'); + } + + // Modify the form based on access controls. + if (!$this->canEditState((object) $data)) + { + // Disable fields for display. + $form->setFieldAttribute('ordering', 'disabled', 'true'); + $form->setFieldAttribute('publish_up', 'disabled', 'true'); + $form->setFieldAttribute('publish_down', 'disabled', 'true'); + $form->setFieldAttribute('state', 'disabled', 'true'); + $form->setFieldAttribute('sticky', 'disabled', 'true'); + + // Disable fields while saving. + // The controller has already verified this is a record you can edit. + $form->setFieldAttribute('ordering', 'filter', 'unset'); + $form->setFieldAttribute('publish_up', 'filter', 'unset'); + $form->setFieldAttribute('publish_down', 'filter', 'unset'); + $form->setFieldAttribute('state', 'filter', 'unset'); + $form->setFieldAttribute('sticky', 'filter', 'unset'); + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $app = JFactory::getApplication(); + $data = $app->getUserState('com_banners.edit.banner.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + + // Prime some default values. + if ($this->getState('banner.id') == 0) + { + $data->set('catid', $app->input->getInt('catid', $app->getUserState('com_banners.banners.filter.category_id'))); + } + } + + $this->preprocessData('com_banners.banner', $data); + + return $data; + } + + /** + * Method to stick records. + * + * @param array &$pks The ids of the items to publish. + * @param integer $value The value of the published state + * + * @return boolean True on success. + * + * @since 1.6 + */ + public function stick(&$pks, $value = 1) + { + $user = JFactory::getUser(); + $table = $this->getTable(); + $pks = (array) $pks; + + // Access checks. + foreach ($pks as $i => $pk) + { + if ($table->load($pk)) + { + if (!$this->canEditState($table)) + { + // Prune items that you can't change. + unset($pks[$i]); + JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED')); + } + } + } + + // Attempt to change the state of the records. + if (!$table->stick($pks, $value, $user->get('id'))) + { + $this->setError($table->getError()); + return false; + } + + return true; + } + + /** + * A protected method to get a set of ordering conditions. + * + * @param JTable $table A record object. + * + * @return array An array of conditions to add to add to ordering queries. + * + * @since 1.6 + */ + protected function getReorderConditions($table) + { + $condition = array(); + $condition[] = 'catid = '. (int) $table->catid; + $condition[] = 'state >= 0'; + return $condition; + } + + /** + * @since 3.0 + */ + protected function prepareTable($table) + { + $date = JFactory::getDate(); + $user = JFactory::getUser(); + + if (empty($table->id)) + { + // Set the values + $table->created = $date->toSql(); + + // Set ordering to the last item if not set + if (empty($table->ordering)) + { + $db = JFactory::getDbo(); + $db->setQuery('SELECT MAX(ordering) FROM #__banners'); + $max = $db->loadResult(); + + $table->ordering = $max + 1; + } + } + else + { + // Set the values + $table->modified = $date->toSql(); + $table->modified_by = $user->get('id'); + } + // Increment the content version number. + $table->version++; + } + + /** + * Method to save the form data. + * + * @param array The form data. + * + * @return boolean True on success. + * @since 1.6 + */ + + public function save($data) + { + $app = JFactory::getApplication(); + + // Alter the name for save as copy + if ($app->input->get('task') == 'save2copy') + { + list($name, $alias) = $this->generateNewTitle($data['catid'], $data['alias'], $data['name']); + $data['name'] = $name; + $data['alias'] = $alias; + $data['state'] = 0; + } + + if (parent::save($data)) + { + return true; + } + + return false; + } + +} diff --git a/administrator/components/com_banners/models/banners.php b/administrator/components/com_banners/models/banners.php new file mode 100644 index 0000000..31983bd --- /dev/null +++ b/administrator/components/com_banners/models/banners.php @@ -0,0 +1,252 @@ +cache['categoryorders'])) + { + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->select('MAX(ordering) as ' . $db->quoteName('max') . ', catid') + ->select('catid') + ->from('#__banners') + ->group('catid'); + $db->setQuery($query); + $this->cache['categoryorders'] = $db->loadAssocList('catid', 0); + } + return $this->cache['categoryorders']; + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery + * @since 1.6 + */ + protected function getListQuery() + { + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.id AS id, a.name AS name, a.alias AS alias,' . + 'a.checked_out AS checked_out,' . + 'a.checked_out_time AS checked_out_time, a.catid AS catid,' . + 'a.clicks AS clicks, a.metakey AS metakey, a.sticky AS sticky,' . + 'a.impmade AS impmade, a.imptotal AS imptotal,' . + 'a.state AS state, a.ordering AS ordering,' . + 'a.purchase_type as purchase_type,' . + 'a.language, a.publish_up, a.publish_down' + ) + ); + $query->from($db->quoteName('#__banners') . ' AS a'); + + // Join over the language + $query->select('l.title AS language_title') + ->join('LEFT', $db->quoteName('#__languages') . ' AS l ON l.lang_code = a.language'); + + // Join over the users for the checked out user. + $query->select('uc.name AS editor') + ->join('LEFT', '#__users AS uc ON uc.id=a.checked_out'); + + // Join over the categories. + $query->select('c.title AS category_title') + ->join('LEFT', '#__categories AS c ON c.id = a.catid'); + + // Join over the clients. + $query->select('cl.name AS client_name,cl.purchase_type as client_purchase_type') + ->join('LEFT', '#__banner_clients AS cl ON cl.id = a.cid'); + + // Filter by published state + $published = $this->getState('filter.state'); + if (is_numeric($published)) + { + $query->where('a.state = ' . (int) $published); + } + elseif ($published === '') + { + $query->where('(a.state IN (0, 1))'); + } + + // Filter by category. + $categoryId = $this->getState('filter.category_id'); + if (is_numeric($categoryId)) + { + $query->where('a.catid = ' . (int) $categoryId); + } + + // Filter by client. + $clientId = $this->getState('filter.client_id'); + if (is_numeric($clientId)) + { + $query->where('a.cid = ' . (int) $clientId); + } + + // Filter by search in title + $search = $this->getState('filter.search'); + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + else + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('(a.name LIKE ' . $search . ' OR a.alias LIKE ' . $search . ')'); + } + } + + // Filter on the language. + if ($language = $this->getState('filter.language')) + { + $query->where('a.language = ' . $db->quote($language)); + } + + // Add the list ordering clause. + $orderCol = $this->state->get('list.ordering', 'ordering'); + $orderDirn = $this->state->get('list.direction', 'ASC'); + if ($orderCol == 'ordering' || $orderCol == 'category_title') + { + $orderCol = 'c.title ' . $orderDirn . ', a.ordering'; + } + if ($orderCol == 'client_name') + { + $orderCol = 'cl.name'; + } + $query->order($db->escape($orderCol . ' ' . $orderDirn)); + + //echo nl2br(str_replace('#__','jos_',$query)); + return $query; + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * @return string A store id. + * @since 1.6 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.access'); + $id .= ':' . $this->getState('filter.state'); + $id .= ':' . $this->getState('filter.category_id'); + $id .= ':' . $this->getState('filter.language'); + + return parent::getStoreId($id); + } + + /** + * Returns a reference to the a Table object, always creating it. + * + * @param type The table type to instantiate + * @param string A prefix for the table class name. Optional. + * @param array Configuration array for model. Optional. + * @return JTable A database object + * @since 1.6 + */ + public function getTable($type = 'Banner', $prefix = 'BannersTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @since 1.6 + */ + protected function populateState($ordering = null, $direction = null) + { + // Load the filter state. + $search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $state = $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string'); + $this->setState('filter.state', $state); + + $categoryId = $this->getUserStateFromRequest($this->context . '.filter.category_id', 'filter_category_id', ''); + $this->setState('filter.category_id', $categoryId); + + $clientId = $this->getUserStateFromRequest($this->context . '.filter.client_id', 'filter_client_id', ''); + $this->setState('filter.client_id', $clientId); + + $language = $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', ''); + $this->setState('filter.language', $language); + + // Load the parameters. + $params = JComponentHelper::getParams('com_banners'); + $this->setState('params', $params); + + // List state information. + parent::populateState('a.name', 'asc'); + } +} diff --git a/administrator/components/com_banners/models/client.php b/administrator/components/com_banners/models/client.php new file mode 100644 index 0000000..af40926 --- /dev/null +++ b/administrator/components/com_banners/models/client.php @@ -0,0 +1,134 @@ +id)) + { + if ($record->state != -2) + { + return; + } + $user = JFactory::getUser(); + + if (!empty($record->catid)) + { + return $user->authorise('core.delete', 'com_banners.category.'.(int) $record->catid); + } + else { + return $user->authorise('core.delete', 'com_banners'); + } + } + } + + /** + * Method to test whether a record can be deleted. + * + * @param object A record object. + * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. + * @since 1.6 + */ + protected function canEditState($record) + { + $user = JFactory::getUser(); + + if (!empty($record->catid)) + { + return $user->authorise('core.edit.state', 'com_banners.category.'.(int) $record->catid); + } + else + { + return $user->authorise('core.edit.state', 'com_banners'); + } + } + + /** + * Returns a reference to the a Table object, always creating it. + * + * @param type The table type to instantiate + * @param string A prefix for the table class name. Optional. + * @param array Configuration array for model. Optional. + * @return JTable A database object + * @since 1.6 + */ + public function getTable($type = 'Client', $prefix = 'BannersTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Method to get the record form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * @return mixed A JForm object on success, false on failure + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + // Get the form. + $form = $this->loadForm('com_banners.client', 'client', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_banners.edit.client.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + } + + $this->preprocessData('com_banners.client', $data); + + return $data; + } + + /** + * Prepare and sanitise the table data prior to saving. + * + * @param JTable A JTable object. + * @since 1.6 + */ + protected function prepareTable($table) + { + $table->name = htmlspecialchars_decode($table->name, ENT_QUOTES); + } +} diff --git a/administrator/components/com_banners/models/clients.php b/administrator/components/com_banners/models/clients.php new file mode 100644 index 0000000..bc18998 --- /dev/null +++ b/administrator/components/com_banners/models/clients.php @@ -0,0 +1,165 @@ +getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $state = $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string'); + $this->setState('filter.state', $state); + + // Load the parameters. + $params = JComponentHelper::getParams('com_banners'); + $this->setState('params', $params); + + // List state information. + parent::populateState('a.name', 'asc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.access'); + $id .= ':' . $this->getState('filter.state'); + + return parent::getStoreId($id); + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.id AS id,' . + 'a.name AS name,' . + 'a.contact AS contact,' . + 'a.checked_out AS checked_out,' . + 'a.checked_out_time AS checked_out_time, ' . + 'a.state AS state,' . + 'a.metakey AS metakey,' . + 'a.purchase_type as purchase_type' + ) + ); + + $query->from($db->quoteName('#__banner_clients') . ' AS a'); + + // Join over the banners for counting + $query->select('COUNT(b.id) as nbanners') + ->join('LEFT', '#__banners AS b ON a.id = b.cid'); + + // Join over the users for the checked out user. + $query->select('uc.name AS editor') + ->join('LEFT', '#__users AS uc ON uc.id=a.checked_out'); + + // Filter by published state + $published = $this->getState('filter.state'); + if (is_numeric($published)) + { + $query->where('a.state = ' . (int) $published); + } + elseif ($published === '') + { + $query->where('(a.state IN (0, 1))'); + } + + $query->group('a.id, a.name, a.contact, a.checked_out, a.checked_out_time, a.state, a.metakey, a.purchase_type, uc.name'); + + // Filter by search in title + $search = $this->getState('filter.search'); + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + else + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('a.name LIKE ' . $search); + } + } + $ordering_o = $this->getState('list.ordering', 'ordering'); + if ($ordering_o == 'nbanners') + { + $ordering_o = 'COUNT(b.id)'; + } + // Add the list ordering clause. + $query->order($db->escape($ordering_o) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))); + + //echo nl2br(str_replace('#__','jos_',$query)); + return $query; + } +} diff --git a/administrator/components/com_banners/models/download.php b/administrator/components/com_banners/models/download.php new file mode 100644 index 0000000..ce48395 --- /dev/null +++ b/administrator/components/com_banners/models/download.php @@ -0,0 +1,79 @@ +input; + + $basename = $input->cookie->getString(JApplication::getHash($this->_context.'.basename'), '__SITE__'); + $this->setState('basename', $basename); + + $compressed = $input->cookie->getInt(JApplication::getHash($this->_context.'.compressed'), 1); + $this->setState('compressed', $compressed); + } + + /** + * Method to get the record form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * + * @return mixed A JForm object on success, false on failure + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + // Get the form. + $form = $this->loadForm('com_banners.download', 'download', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * @since 1.6 + */ + protected function loadFormData() + { + $data = array( + 'basename' => $this->getState('basename'), + 'compressed' => $this->getState('compressed') + ); + + $this->preprocessData('com_banners.download', $data); + + return $data; + } +} diff --git a/administrator/components/com_banners/models/fields/bannerclient.php b/administrator/components/com_banners/models/fields/bannerclient.php new file mode 100644 index 0000000..4f34a92 --- /dev/null +++ b/administrator/components/com_banners/models/fields/bannerclient.php @@ -0,0 +1,43 @@ +id.'\').value=\'0\';"'; + + return ' ' . JText::_('COM_BANNERS_RESET_CLICKS') . ''; + } +} diff --git a/administrator/components/com_banners/models/fields/impmade.php b/administrator/components/com_banners/models/fields/impmade.php new file mode 100644 index 0000000..56c453f --- /dev/null +++ b/administrator/components/com_banners/models/fields/impmade.php @@ -0,0 +1,41 @@ +id.'\').value=\'0\';"'; + + return ' '.JText::_('COM_BANNERS_RESET_IMPMADE').''; + } +} diff --git a/administrator/components/com_banners/models/fields/imptotal.php b/administrator/components/com_banners/models/fields/imptotal.php new file mode 100644 index 0000000..b6c5e28 --- /dev/null +++ b/administrator/components/com_banners/models/fields/imptotal.php @@ -0,0 +1,47 @@ +id.'_unlimited\').checked=document.id(\''.$this->id.'\').value==\'\';"'; + $onclick = ' onclick="if (document.id(\''.$this->id.'_unlimited\').checked) document.id(\''.$this->id.'\').value=\'\';"'; + $value = empty($this->value) ? '' : $this->value; + $checked = empty($this->value) ? ' checked="checked"' : ''; + + return ' +
+
'; + } +} diff --git a/administrator/components/com_banners/models/fields/index.html b/administrator/components/com_banners/models/fields/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/models/fields/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/models/fields/ordering.php b/administrator/components/com_banners/models/fields/ordering.php new file mode 100644 index 0000000..1ea55ef --- /dev/null +++ b/administrator/components/com_banners/models/fields/ordering.php @@ -0,0 +1,71 @@ +element['class'] ? ' class="'.(string) $this->element['class'].'"' : ''; + $attr .= ((string) $this->element['disabled'] == 'true') ? ' disabled="disabled"' : ''; + $attr .= $this->element['size'] ? ' size="'.(int) $this->element['size'].'"' : ''; + + // Initialize JavaScript field attributes. + $attr .= $this->element['onchange'] ? ' onchange="'.(string) $this->element['onchange'].'"' : ''; + + // Get some field values from the form. + $bannerId = (int) $this->form->getValue('id'); + $categoryId = (int) $this->form->getValue('catid'); + + // Build the query for the ordering list. + $query = 'SELECT ordering AS value, name AS text' . + ' FROM #__banners' . + ' WHERE catid = ' . (int) $categoryId . + ' ORDER BY ordering'; + + // Create a read-only list (no name) with a hidden input to store the value. + if ((string) $this->element['readonly'] == 'true') + { + $html[] = JHtml::_('list.ordering', '', $query, trim($attr), $this->value, $bannerId ? 0 : 1); + $html[] = ''; + } + // Create a regular list. + else { + $html[] = JHtml::_('list.ordering', $this->name, $query, trim($attr), $this->value, $bannerId ? 0 : 1); + } + + return implode($html); + } +} diff --git a/administrator/components/com_banners/models/forms/banner.xml b/administrator/components/com_banners/models/forms/banner.xml new file mode 100644 index 0000000..f8428ab --- /dev/null +++ b/administrator/components/com_banners/models/forms/banner.xml @@ -0,0 +1,219 @@ + +
+
+ + + + + + + + > + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + +
+ + +
+ + + + + +
+
+ +
+ +
+ +
diff --git a/administrator/components/com_banners/models/forms/client.xml b/administrator/components/com_banners/models/forms/client.xml new file mode 100644 index 0000000..5b79f37 --- /dev/null +++ b/administrator/components/com_banners/models/forms/client.xml @@ -0,0 +1,103 @@ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + +
+ +
+ + + +
+
diff --git a/administrator/components/com_banners/models/forms/download.xml b/administrator/components/com_banners/models/forms/download.xml new file mode 100644 index 0000000..b69d222 --- /dev/null +++ b/administrator/components/com_banners/models/forms/download.xml @@ -0,0 +1,19 @@ + +
+
+ + + + + + + + +
+
diff --git a/administrator/components/com_banners/models/forms/index.html b/administrator/components/com_banners/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/models/index.html b/administrator/components/com_banners/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/models/tracks.php b/administrator/components/com_banners/models/tracks.php new file mode 100644 index 0000000..dd9951a --- /dev/null +++ b/administrator/components/com_banners/models/tracks.php @@ -0,0 +1,515 @@ +getUserStateFromRequest($this->context . '.filter.type', 'filter_type'); + $this->setState('filter.type', $type); + + $begin = $this->getUserStateFromRequest($this->context . '.filter.begin', 'filter_begin', '', 'string'); + $this->setState('filter.begin', $begin); + + $end = $this->getUserStateFromRequest($this->context . '.filter.end', 'filter_end', '', 'string'); + $this->setState('filter.end', $end); + + $categoryId = $this->getUserStateFromRequest($this->context . '.filter.category_id', 'filter_category_id', ''); + $this->setState('filter.category_id', $categoryId); + + $clientId = $this->getUserStateFromRequest($this->context . '.filter.client_id', 'filter_client_id', ''); + $this->setState('filter.client_id', $clientId); + + // Load the parameters. + $params = JComponentHelper::getParams('com_banners'); + $this->setState('params', $params); + + // List state information. + parent::populateState('b.name', 'asc'); + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery + * @since 1.6 + */ + protected function getListQuery() + { + require_once JPATH_COMPONENT . '/helpers/banners.php'; + + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Select the required fields from the table. + $query->select( + 'a.track_date as track_date,' + . 'a.track_type as track_type,' + . $db->quoteName('a.count') . ' as ' . $db->quoteName('count') + ); + $query->from($db->quoteName('#__banner_tracks') . ' AS a'); + + // Join with the banners + $query->join('LEFT', $db->quoteName('#__banners') . ' as b ON b.id=a.banner_id') + ->select('b.name as name'); + + // Join with the client + $query->join('LEFT', $db->quoteName('#__banner_clients') . ' as cl ON cl.id=b.cid') + ->select('cl.name as client_name'); + + // Join with the category + $query->join('LEFT', $db->quoteName('#__categories') . ' as cat ON cat.id=b.catid') + ->select('cat.title as category_title'); + + // Filter by type + $type = $this->getState('filter.type'); + if (!empty($type)) + { + $query->where('a.track_type = ' . (int) $type); + } + + // Filter by client + $clientId = $this->getState('filter.client_id'); + if (is_numeric($clientId)) + { + $query->where('b.cid = ' . (int) $clientId); + } + + // Filter by category + $catedoryId = $this->getState('filter.category_id'); + if (is_numeric($catedoryId)) + { + $query->where('b.catid = ' . (int) $catedoryId); + } + + // Filter by begin date + + $begin = $this->getState('filter.begin'); + if (!empty($begin)) + { + $query->where('a.track_date >= ' . $db->quote($begin)); + } + + // Filter by end date + $end = $this->getState('filter.end'); + if (!empty($end)) + { + $query->where('a.track_date <= ' . $db->quote($end)); + } + + // Add the list ordering clause. + $orderCol = $this->getState('list.ordering', 'name'); + $query->order($db->escape($orderCol) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))); + + return $query; + } + + /** + * Method to delete rows. + * + * @param array An array of item ids. + * + * @return boolean Returns true on success, false on failure. + */ + public function delete() + { + $user = JFactory::getUser(); + $categoryId = $this->getState('category_id'); + + // Access checks. + if ($categoryId) + { + $allow = $user->authorise('core.delete', 'com_banners.category.' . (int) $categoryId); + } + else + { + $allow = $user->authorise('core.delete', 'com_banners'); + } + + if ($allow) + { + // Delete tracks from this banner + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->delete($db->quoteName('#__banner_tracks')); + + // Filter by type + $type = $this->getState('filter.type'); + if (!empty($type)) + { + $query->where('track_type = ' . (int) $type); + } + + // Filter by begin date + $begin = $this->getState('filter.begin'); + if (!empty($begin)) + { + $query->where('track_date >= ' . $db->quote($begin)); + } + + // Filter by end date + $end = $this->getState('filter.end'); + if (!empty($end)) + { + $query->where('track_date <= ' . $db->quote($end)); + } + + $where = '1'; + // Filter by client + $clientId = $this->getState('filter.client_id'); + if (!empty($clientId)) + { + $where .= ' AND cid = ' . (int) $clientId; + } + + // Filter by category + if (!empty($categoryId)) + { + $where .= ' AND catid = ' . (int) $categoryId; + } + + $query->where('banner_id IN (SELECT id FROM ' . $db->quoteName('#__banners') . ' WHERE ' . $where . ')'); + + $db->setQuery($query); + $this->setError((string) $query); + + try + { + $db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + } + else + { + JError::raiseWarning(403, JText::_('JERROR_CORE_DELETE_NOT_PERMITTED')); + } + + return true; + } + + /** + * Get file name + * + * @return string The file name + * @since 1.6 + */ + public function getBaseName() + { + if (!isset($this->basename)) + { + + $app = JFactory::getApplication(); + $basename = $this->getState('basename'); + $basename = str_replace('__SITE__', $app->getCfg('sitename'), $basename); + $categoryId = $this->getState('filter.category_id'); + + if (is_numeric($categoryId)) + { + if ($categoryId > 0) + { + $basename = str_replace('__CATID__', $categoryId, $basename); + } + else + { + $basename = str_replace('__CATID__', '', $basename); + } + $categoryName = $this->getCategoryName(); + $basename = str_replace('__CATNAME__', $categoryName, $basename); + } + else + { + $basename = str_replace('__CATID__', '', $basename); + $basename = str_replace('__CATNAME__', '', $basename); + } + + $clientId = $this->getState('filter.client_id'); + if (is_numeric($clientId)) + { + + if ($clientId > 0) + { + $basename = str_replace('__CLIENTID__', $clientId, $basename); + } + else + { + $basename = str_replace('__CLIENTID__', '', $basename); + } + $clientName = $this->getClientName(); + $basename = str_replace('__CLIENTNAME__', $clientName, $basename); + } + else + { + + $basename = str_replace('__CLIENTID__', '', $basename); + $basename = str_replace('__CLIENTNAME__', '', $basename); + } + + $type = $this->getState('filter.type'); + if ($type > 0) + { + + $basename = str_replace('__TYPE__', $type, $basename); + $typeName = JText::_('COM_BANNERS_TYPE' . $type); + $basename = str_replace('__TYPENAME__', $typeName, $basename); + } + else + { + $basename = str_replace('__TYPE__', '', $basename); + $basename = str_replace('__TYPENAME__', '', $basename); + } + + $begin = $this->getState('filter.begin'); + if (!empty($begin)) + { + $basename = str_replace('__BEGIN__', $begin, $basename); + } + else + { + $basename = str_replace('__BEGIN__', '', $basename); + } + + $end = $this->getState('filter.end'); + if (!empty($end)) + { + $basename = str_replace('__END__', $end, $basename); + } + else + { + $basename = str_replace('__END__', '', $basename); + } + + $this->basename = $basename; + } + + return $this->basename; + } + + /** + * Get the category name. + * + * @return string The category name + * @since 1.6 + */ + protected function getCategoryName() + { + $categoryId = $this->getState('filter.category_id'); + + if ($categoryId) + { + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->select('title') + ->from($db->quoteName('#__categories')) + ->where($db->quoteName('id') . '=' . $db->quote($categoryId)); + $db->setQuery($query); + + try + { + $name = $db->loadResult(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + } + else + { + $name = JText::_('COM_BANNERS_NOCATEGORYNAME'); + } + + return $name; + } + + /** + * Get the category name + * + * @return string The category name. + * @since 1.6 + */ + protected function getClientName() + { + $clientId = $this->getState('filter.client_id'); + + if ($clientId) + { + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->select('name') + ->from($db->quoteName('#__banner_clients')) + ->where($db->quoteName('id') . '=' . $db->quote($clientId)); + $db->setQuery($query); + + try + { + $name = $db->loadResult(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + } + else + { + $name = JText::_('COM_BANNERS_NOCLIENTNAME'); + } + + return $name; + } + + /** + * Get the file type. + * + * @return string The file type + * @since 1.6 + */ + public function getFileType() + { + return $this->getState('compressed') ? 'zip' : 'csv'; + } + + /** + * Get the mime type. + * + * @return string The mime type. + * @since 1.6 + */ + public function getMimeType() + { + return $this->getState('compressed') ? 'application/zip' : 'text/csv'; + } + + /** + * Get the content + * + * @return string The content. + * @since 1.6 + */ + public function getContent() + { + if (!isset($this->content)) + { + + $this->content = ''; + $this->content .= + '"' . str_replace('"', '""', JText::_('COM_BANNERS_HEADING_NAME')) . '","' . + str_replace('"', '""', JText::_('COM_BANNERS_HEADING_CLIENT')) . '","' . + str_replace('"', '""', JText::_('JCATEGORY')) . '","' . + str_replace('"', '""', JText::_('COM_BANNERS_HEADING_TYPE')) . '","' . + str_replace('"', '""', JText::_('COM_BANNERS_HEADING_COUNT')) . '","' . + str_replace('"', '""', JText::_('JDATE')) . '"' . "\n"; + + foreach ($this->getItems() as $item) + { + + $this->content .= + '"' . str_replace('"', '""', $item->name) . '","' . + str_replace('"', '""', $item->client_name) . '","' . + str_replace('"', '""', $item->category_title) . '","' . + str_replace('"', '""', ($item->track_type == 1 ? JText::_('COM_BANNERS_IMPRESSION') : JText::_('COM_BANNERS_CLICK'))) . '","' . + str_replace('"', '""', $item->count) . '","' . + str_replace('"', '""', $item->track_date) . '"' . "\n"; + } + + if ($this->getState('compressed')) + { + $app = JFactory::getApplication('administrator'); + + $files = array(); + $files['track'] = array(); + $files['track']['name'] = $this->getBasename() . '.csv'; + $files['track']['data'] = $this->content; + $files['track']['time'] = time(); + $ziproot = $app->getCfg('tmp_path') . '/' . uniqid('banners_tracks_') . '.zip'; + + // run the packager + jimport('joomla.filesystem.folder'); + jimport('joomla.filesystem.file'); + $delete = JFolder::files($app->getCfg('tmp_path') . '/', uniqid('banners_tracks_'), false, true); + + if (!empty($delete)) + { + if (!JFile::delete($delete)) + { + // JFile::delete throws an error + $this->setError(JText::_('COM_BANNERS_ERR_ZIP_DELETE_FAILURE')); + return false; + } + } + + if (!$packager = JArchive::getAdapter('zip')) + { + $this->setError(JText::_('COM_BANNERS_ERR_ZIP_ADAPTER_FAILURE')); + return false; + } + elseif (!$packager->create($ziproot, $files)) + { + $this->setError(JText::_('COM_BANNERS_ERR_ZIP_CREATE_FAILURE')); + return false; + } + + $this->content = file_get_contents($ziproot); + } + } + + return $this->content; + } +} diff --git a/administrator/components/com_banners/sql/index.html b/administrator/components/com_banners/sql/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/sql/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/sql/install.mysql.utf8.sql b/administrator/components/com_banners/sql/install.mysql.utf8.sql new file mode 100644 index 0000000..e123c0c --- /dev/null +++ b/administrator/components/com_banners/sql/install.mysql.utf8.sql @@ -0,0 +1,69 @@ +CREATE TABLE `#__banners` ( + `id` INTEGER NOT NULL auto_increment, + `cid` INTEGER NOT NULL DEFAULT '0', + `type` INTEGER NOT NULL DEFAULT '0', + `name` VARCHAR(255) NOT NULL DEFAULT '', + `alias` VARCHAR(255) NOT NULL DEFAULT '', + `imptotal` INTEGER NOT NULL DEFAULT '0', + `impmade` INTEGER NOT NULL DEFAULT '0', + `clicks` INTEGER NOT NULL DEFAULT '0', + `clickurl` VARCHAR(200) NOT NULL DEFAULT '', + `state` TINYINT(3) NOT NULL DEFAULT '0', + `catid` INTEGER UNSIGNED NOT NULL DEFAULT 0, + `description` TEXT NOT NULL, + `custombannercode` VARCHAR(2048) NOT NULL, + `sticky` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0, + `ordering` INTEGER NOT NULL DEFAULT 0, + `metakey` TEXT NOT NULL, + `params` TEXT NOT NULL, + `own_prefix` TINYINT(1) NOT NULL DEFAULT '0', + `metakey_prefix` VARCHAR(255) NOT NULL DEFAULT '', + `purchase_type` TINYINT NOT NULL DEFAULT '-1', + `track_clicks` TINYINT NOT NULL DEFAULT '-1', + `track_impressions` TINYINT NOT NULL DEFAULT '-1', + `checked_out` INTEGER UNSIGNED NOT NULL DEFAULT '0', + `checked_out_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `publish_up` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `publish_down` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `reset` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `language` char(7) NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + INDEX `idx_state` (`state`), + INDEX `idx_own_prefix` (`own_prefix`), + INDEX `idx_metakey_prefix` (`metakey_prefix`), + INDEX `idx_banner_catid`(`catid`), + INDEX `idx_language` (`language`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE `#__banner_clients` ( + `id` INTEGER NOT NULL auto_increment, + `name` VARCHAR(255) NOT NULL DEFAULT '', + `contact` VARCHAR(255) NOT NULL DEFAULT '', + `email` VARCHAR(255) NOT NULL DEFAULT '', + `extrainfo` TEXT NOT NULL, + `state` TINYINT(3) NOT NULL DEFAULT '0', + `checked_out` INTEGER UNSIGNED NOT NULL DEFAULT '0', + `checked_out_time` DATETIME NOT NULL default '0000-00-00 00:00:00', + `metakey` TEXT NOT NULL, + `own_prefix` TINYINT NOT NULL DEFAULT '0', + `metakey_prefix` VARCHAR(255) NOT NULL default '', + `purchase_type` TINYINT NOT NULL DEFAULT '-1', + `track_clicks` TINYINT NOT NULL DEFAULT '-1', + `track_impressions` TINYINT NOT NULL DEFAULT '-1', + PRIMARY KEY (`id`), + INDEX `idx_own_prefix` (`own_prefix`), + INDEX `idx_metakey_prefix` (`metakey_prefix`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE `#__banner_tracks` ( + `track_date` DATETIME NOT NULL, + `track_type` INTEGER UNSIGNED NOT NULL, + `banner_id` INTEGER UNSIGNED NOT NULL, + `count` INTEGER UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`track_date`, `track_type`, `banner_id`), + INDEX `idx_track_date` (`track_date`), + INDEX `idx_track_type` (`track_type`), + INDEX `idx_banner_id` (`banner_id`) +) DEFAULT CHARSET=utf8; + diff --git a/administrator/components/com_banners/sql/uninstall.mysql.utf8.sql b/administrator/components/com_banners/sql/uninstall.mysql.utf8.sql new file mode 100644 index 0000000..19fc08f --- /dev/null +++ b/administrator/components/com_banners/sql/uninstall.mysql.utf8.sql @@ -0,0 +1,6 @@ +DROP TABLE IF EXISTS `#__banners`; + +DROP TABLE IF EXISTS `#__banner_clients`; + +DROP TABLE IF EXISTS `#__banner_tracks`; + diff --git a/administrator/components/com_banners/tables/banner.php b/administrator/components/com_banners/tables/banner.php new file mode 100644 index 0000000..cefb6c0 --- /dev/null +++ b/administrator/components/com_banners/tables/banner.php @@ -0,0 +1,338 @@ +created = $date->toSql(); + } + + public function clicks() + { + $query = 'UPDATE #__banners' + . ' SET clicks = (clicks + 1)' + . ' WHERE id = ' . (int) $this->id; + + $this->_db->setQuery($query); + $this->_db->execute(); + } + + /** + * Overloaded check function + * + * @return boolean + * @see JTable::check + * @since 1.5 + */ + public function check() + { + // Set name + $this->name = htmlspecialchars_decode($this->name, ENT_QUOTES); + + // Set alias + $this->alias = JApplication::stringURLSafe($this->alias); + if (empty($this->alias)) + { + $this->alias = JApplication::stringURLSafe($this->name); + } + + // Check the publish down date is not earlier than publish up. + if ($this->publish_down > $this->_db->getNullDate() && $this->publish_down < $this->publish_up) + { + $this->setError(JText::_('JGLOBAL_START_PUBLISH_AFTER_FINISH')); + return false; + } + + // Set ordering + if ($this->state < 0) + { + // Set ordering to 0 if state is archived or trashed + $this->ordering = 0; + } elseif (empty($this->ordering)) + { + // Set ordering to last if ordering was 0 + $this->ordering = self::getNextOrder($this->_db->quoteName('catid').'=' . $this->_db->quote($this->catid).' AND state>=0'); + } + + return true; + } + + /** + * Overloaded bind function + * + * @param array $hash named array + * @return null|string null is operation was satisfactory, otherwise returns an error + * @see JTable:bind + * @since 1.5 + */ + public function bind($array, $ignore = array()) + { + if (isset($array['params']) && is_array($array['params'])) + { + $registry = new JRegistry; + $registry->loadArray($array['params']); + + if ((int) $registry->get('width', 0) < 0){ + $this->setError(JText::sprintf('JLIB_DATABASE_ERROR_NEGATIVE_NOT_PERMITTED', JText::_('COM_BANNERS_FIELD_WIDTH_LABEL'))); + return false; + } + + if ((int) $registry->get('height', 0) < 0){ + $this->setError(JText::sprintf('JLIB_DATABASE_ERROR_NEGATIVE_NOT_PERMITTED', JText::_('COM_BANNERS_FIELD_HEIGHT_LABEL'))); + return false; + } + + // Converts the width and height to an absolute numeric value: + $width = abs((int) $registry->get('width', 0)); + $height = abs((int) $registry->get('height', 0)); + + // Sets the width and height to an empty string if = 0 + $registry->set('width', ($width ? $width : '')); + $registry->set('height', ($height ? $height : '')); + + $array['params'] = (string) $registry; + } + + if (isset($array['imptotal'])) + { + $array['imptotal'] = abs((int) $array['imptotal']); + } + + return parent::bind($array, $ignore); + } + /** + * Method to store a row + * + * @param boolean $updateNulls True to update fields even if they are null. + */ + public function store($updateNulls = false) + { + if (empty($this->id)) + { + $purchase_type = $this->purchase_type; + if ($purchase_type < 0 && $this->cid) + { + $client = JTable::getInstance('Client', 'BannersTable'); + $client->load($this->cid); + $purchase_type = $client->purchase_type; + } + if ($purchase_type < 0) + { + $params = JComponentHelper::getParams('com_banners'); + $purchase_type = $params->get('purchase_type'); + } + + switch($purchase_type) + { + case 1: + $this->reset = $this->_db->getNullDate(); + break; + case 2: + $date = JFactory::getDate('+1 year '.date('Y-m-d', strtotime('now'))); + $this->reset = $this->_db->quote($date->toSql()); + break; + case 3: + $date = JFactory::getDate('+1 month '.date('Y-m-d', strtotime('now'))); + $this->reset = $this->_db->quote($date->toSql()); + break; + case 4: + $date = JFactory::getDate('+7 day '.date('Y-m-d', strtotime('now'))); + $this->reset = $this->_db->quote($date->toSql()); + break; + case 5: + $date = JFactory::getDate('+1 day '.date('Y-m-d', strtotime('now'))); + $this->reset = $this->_db->quote($date->toSql()); + break; + } + // Store the row + parent::store($updateNulls); + } + else + { + // Get the old row + $oldrow = JTable::getInstance('Banner', 'BannersTable'); + if (!$oldrow->load($this->id) && $oldrow->getError()) + { + $this->setError($oldrow->getError()); + } + + // Verify that the alias is unique + $table = JTable::getInstance('Banner', 'BannersTable'); + if ($table->load(array('alias' => $this->alias, 'catid' => $this->catid)) && ($table->id != $this->id || $this->id == 0)) + { + $this->setError(JText::_('COM_BANNERS_ERROR_UNIQUE_ALIAS')); + return false; + } + + // Store the new row + parent::store($updateNulls); + + // Need to reorder ? + if ($oldrow->state >= 0 && ($this->state < 0 || $oldrow->catid != $this->catid)) + { + // Reorder the oldrow + $this->reorder($this->_db->quoteName('catid').'=' . $this->_db->quote($oldrow->catid).' AND state>=0'); + } + } + return count($this->getErrors()) == 0; + } + + /** + * Method to set the publishing state for a row or list of rows in the database + * table. The method respects checked out rows by other users and will attempt + * to checkin rows that it can after adjustments are made. + * + * @param mixed An optional array of primary key values to update. If not + * set the instance property value is used. + * @param integer The publishing state. eg. [0 = unpublished, 1 = published, 2=archived, -2=trashed] + * @param integer The user id of the user performing the operation. + * @return boolean True on success. + * @since 1.6 + */ + public function publish($pks = null, $state = 1, $userId = 0) + { + $k = $this->_tbl_key; + + // Sanitize input. + JArrayHelper::toInteger($pks); + $userId = (int) $userId; + $state = (int) $state; + + // If there are no primary keys set check to see if the instance key is set. + if (empty($pks)) + { + if ($this->$k) + { + $pks = array($this->$k); + } + // Nothing to set publishing state on, return false. + else { + $this->setError(JText::_('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED')); + return false; + } + } + + // Get an instance of the table + $table = JTable::getInstance('Banner', 'BannersTable'); + + // For all keys + foreach ($pks as $pk) + { + // Load the banner + if (!$table->load($pk)) + { + $this->setError($table->getError()); + } + + // Verify checkout + if ($table->checked_out == 0 || $table->checked_out == $userId) + { + // Change the state + $table->state = $state; + $table->checked_out = 0; + $table->checked_out_time = $this->_db->getNullDate(); + + // Check the row + $table->check(); + + // Store the row + if (!$table->store()) + { + $this->setError($table->getError()); + } + } + } + return count($this->getErrors()) == 0; + } + + /** + * Method to set the sticky state for a row or list of rows in the database + * table. The method respects checked out rows by other users and will attempt + * to checkin rows that it can after adjustments are made. + * + * @param mixed An optional array of primary key values to update. If not + * set the instance property value is used. + * @param integer The sticky state. eg. [0 = unsticked, 1 = sticked] + * @param integer The user id of the user performing the operation. + * @return boolean True on success. + * @since 1.6 + */ + public function stick($pks = null, $state = 1, $userId = 0) + { + $k = $this->_tbl_key; + + // Sanitize input. + JArrayHelper::toInteger($pks); + $userId = (int) $userId; + $state = (int) $state; + + // If there are no primary keys set check to see if the instance key is set. + if (empty($pks)) + { + if ($this->$k) + { + $pks = array($this->$k); + } + // Nothing to set publishing state on, return false. + else { + $this->setError(JText::_('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED')); + return false; + } + } + + // Get an instance of the table + $table = JTable::getInstance('Banner', 'BannersTable'); + + // For all keys + foreach ($pks as $pk) + { + // Load the banner + if (!$table->load($pk)) + { + $this->setError($table->getError()); + } + + // Verify checkout + if ($table->checked_out == 0 || $table->checked_out == $userId) + { + // Change the state + $table->sticky = $state; + $table->checked_out = 0; + $table->checked_out_time = $this->_db->getNullDate(); + + // Check the row + $table->check(); + + // Store the row + if (!$table->store()) + { + $this->setError($table->getError()); + } + } + } + return count($this->getErrors()) == 0; + } +} diff --git a/administrator/components/com_banners/tables/client.php b/administrator/components/com_banners/tables/client.php new file mode 100644 index 0000000..a0e1a9f --- /dev/null +++ b/administrator/components/com_banners/tables/client.php @@ -0,0 +1,112 @@ +checked_out_time = $_db->getNullDate(); + parent::__construct('#__banner_clients', 'id', $_db); + } + + /** + * Method to set the publishing state for a row or list of rows in the database + * table. The method respects checked out rows by other users and will attempt + * to checkin rows that it can after adjustments are made. + * + * @param mixed An optional array of primary key values to update. If not + * set the instance property value is used. + * @param integer The publishing state. eg. [0 = unpublished, 1 = published] + * @param integer The user id of the user performing the operation. + * @return boolean True on success. + * @since 1.0.4 + */ + public function publish($pks = null, $state = 1, $userId = 0) + { + $k = $this->_tbl_key; + + // Sanitize input. + JArrayHelper::toInteger($pks); + $userId = (int) $userId; + $state = (int) $state; + + // If there are no primary keys set check to see if the instance key is set. + if (empty($pks)) + { + if ($this->$k) + { + $pks = array($this->$k); + } + // Nothing to set publishing state on, return false. + else { + $this->setError(JText::_('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED')); + return false; + } + } + + // Build the WHERE clause for the primary keys. + $where = $k.'='.implode(' OR '.$k.'=', $pks); + + // Determine if there is checkin support for the table. + if (!property_exists($this, 'checked_out') || !property_exists($this, 'checked_out_time')) + { + $checkin = ''; + } + else + { + $checkin = ' AND (checked_out = 0 OR checked_out = '.(int) $userId.')'; + } + + // Update the publishing state for rows with the given primary keys. + $this->_db->setQuery( + 'UPDATE '.$this->_db->quoteName($this->_tbl). + ' SET '.$this->_db->quoteName('state').' = '.(int) $state . + ' WHERE ('.$where.')' . + $checkin + ); + + try + { + $this->_db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + // If checkin is supported and all rows were adjusted, check them in. + if ($checkin && (count($pks) == $this->_db->getAffectedRows())) + { + // Checkin the rows. + foreach ($pks as $pk) + { + $this->checkin($pk); + } + } + + // If the JTable instance value is in the list of primary keys that were set, set the instance. + if (in_array($this->$k, $pks)) + { + $this->state = $state; + } + + $this->setError(''); + return true; + } +} diff --git a/administrator/components/com_banners/tables/index.html b/administrator/components/com_banners/tables/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/tables/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/banner/index.html b/administrator/components/com_banners/views/banner/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/views/banner/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/banner/tmpl/edit.php b/administrator/components/com_banners/views/banner/tmpl/edit.php new file mode 100644 index 0000000..1cde227 --- /dev/null +++ b/administrator/components/com_banners/views/banner/tmpl/edit.php @@ -0,0 +1,220 @@ + + + + diff --git a/administrator/components/com_banners/views/banner/tmpl/index.html b/administrator/components/com_banners/views/banner/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/views/banner/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/banner/view.html.php b/administrator/components/com_banners/views/banner/view.html.php new file mode 100644 index 0000000..2005af5 --- /dev/null +++ b/administrator/components/com_banners/views/banner/view.html.php @@ -0,0 +1,98 @@ +form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + JFactory::getApplication()->input->set('hidemainmenu', true); + + $user = JFactory::getUser(); + $userId = $user->get('id'); + $isNew = ($this->item->id == 0); + $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $userId); + // Since we don't track these assets at the item level, use the category id. + $canDo = BannersHelper::getActions($this->item->catid, 0); + + JToolbarHelper::title($isNew ? JText::_('COM_BANNERS_MANAGER_BANNER_NEW') : JText::_('COM_BANNERS_MANAGER_BANNER_EDIT'), 'banners.png'); + + // If not checked out, can save the item. + if (!$checkedOut && ($canDo->get('core.edit') || count($user->getAuthorisedCategories('com_banners', 'core.create')) > 0)) + { + JToolbarHelper::apply('banner.apply'); + JToolbarHelper::save('banner.save'); + + if ($canDo->get('core.create')) + { + JToolbarHelper::save2new('banner.save2new'); + } + } + + // If an existing item, can save to a copy. + if (!$isNew && $canDo->get('core.create')) + { + JToolbarHelper::save2copy('banner.save2copy'); + } + + if (empty($this->item->id)) + { + JToolbarHelper::cancel('banner.cancel'); + } + else + { + JToolbarHelper::cancel('banner.cancel', 'JTOOLBAR_CLOSE'); + } + + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_COMPONENTS_BANNERS_BANNERS_EDIT'); + } +} diff --git a/administrator/components/com_banners/views/banners/index.html b/administrator/components/com_banners/views/banners/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/views/banners/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/banners/tmpl/default.php b/administrator/components/com_banners/views/banners/tmpl/default.php new file mode 100644 index 0000000..01a627a --- /dev/null +++ b/administrator/components/com_banners/views/banners/tmpl/default.php @@ -0,0 +1,255 @@ +get('id'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$canOrder = $user->authorise('core.edit.state', 'com_banners.category'); +$archived = $this->state->get('filter.published') == 2 ? true : false; +$trashed = $this->state->get('filter.published') == -2 ? true : false; +$params = (isset($this->state->params)) ? $this->state->params : new JObject; +$saveOrder = $listOrder == 'ordering'; +if ($saveOrder) +{ + $saveOrderingUrl = 'index.php?option=com_banners&task=banners.saveOrderAjax&tmpl=component'; + JHtml::_('sortablelist.sortable', 'articleList', 'adminForm', strtolower($listDirn), $saveOrderingUrl); +} +$sortFields = $this->getSortFields(); +?> + +
+sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ +
+ +
+ + +
+
+ + pagination->getLimitBox(); ?> +
+
+ + +
+
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + items as $i => $item) : + $ordering = ($listOrder == 'ordering'); + $item->cat_link = JRoute::_('index.php?option=com_categories&extension=com_banners&task=edit&type=other&cid[]='. $item->catid); + $canCreate = $user->authorise('core.create', 'com_banners.category.' . $item->catid); + $canEdit = $user->authorise('core.edit', 'com_banners.category.' . $item->catid); + $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $userId || $item->checked_out == 0; + $canChange = $user->authorise('core.edit.state', 'com_banners.category.' . $item->catid) && $canCheckin; + ?> + + + + + + + + + + + + + + + +
+ ', 'ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING'); ?> + + + + + + + + + + + + + + + + + + +
+ pagination->getListFooter(); ?> +
+ + + + + + + + + id); ?> + + state, $i, 'banners.', $canChange, 'cb', $item->publish_up, $item->publish_down); ?> + +
+ checked_out) : ?> + editor, $item->checked_out_time, 'banners.', $canCheckin); ?> + + + + escape($item->name); ?> + + escape($item->name); ?> + +
+ escape($item->category_title); ?> +
+
+
+ id, 'banner.'); + JHtml::_('dropdown.divider'); + if ($item->state) : + JHtml::_('dropdown.unpublish', 'cb' . $i, 'banners.'); + else : + JHtml::_('dropdown.publish', 'cb' . $i, 'banners.'); + endif; + + JHtml::_('dropdown.divider'); + + if ($archived) : + JHtml::_('dropdown.unarchive', 'cb' . $i, 'banners.'); + else : + JHtml::_('dropdown.archive', 'cb' . $i, 'banners.'); + endif; + + if ($item->checked_out) : + JHtml::_('dropdown.checkin', 'cb' . $i, 'banners.'); + endif; + + if ($trashed) : + JHtml::_('dropdown.untrash', 'cb' . $i, 'banners.'); + else : + JHtml::_('dropdown.trash', 'cb' . $i, 'banners.'); + endif; + + // render dropdown list + echo JHtml::_('dropdown.render'); + ?> +
+
+ sticky, $i, $canChange); ?> + + client_name;?> + + impmade, $item->imptotal ? $item->imptotal : JText::_('COM_BANNERS_UNLIMITED'));?> + + clicks;?> - + impmade ? 100 * $item->clicks / $item->impmade : 0);?> + + language == '*'):?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + id; ?> +
+ + loadTemplate('batch'); ?> + + + + + + +
+ diff --git a/administrator/components/com_banners/views/banners/tmpl/default_batch.php b/administrator/components/com_banners/views/banners/tmpl/default_batch.php new file mode 100644 index 0000000..352f17f --- /dev/null +++ b/administrator/components/com_banners/views/banners/tmpl/default_batch.php @@ -0,0 +1,47 @@ +state->get('filter.published'); +?> + diff --git a/administrator/components/com_banners/views/banners/tmpl/index.html b/administrator/components/com_banners/views/banners/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/views/banners/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/banners/view.html.php b/administrator/components/com_banners/views/banners/view.html.php new file mode 100644 index 0000000..57e88f9 --- /dev/null +++ b/administrator/components/com_banners/views/banners/view.html.php @@ -0,0 +1,193 @@ +categories = $this->get('CategoryOrders'); + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + BannersHelper::addSubmenu('banners'); + + $this->addToolbar(); + require_once JPATH_COMPONENT . '/models/fields/bannerclient.php'; + + // Include the component HTML helpers. + JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html'); + + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.6 + */ + protected function addToolbar() + { + require_once JPATH_COMPONENT . '/helpers/banners.php'; + + $canDo = BannersHelper::getActions($this->state->get('filter.category_id')); + $user = JFactory::getUser(); + // Get the toolbar object instance + $bar = JToolBar::getInstance('toolbar'); + + JToolbarHelper::title(JText::_('COM_BANNERS_MANAGER_BANNERS'), 'banners.png'); + if (count($user->getAuthorisedCategories('com_banners', 'core.create')) > 0) + { + JToolbarHelper::addNew('banner.add'); + } + + if (($canDo->get('core.edit'))) + { + JToolbarHelper::editList('banner.edit'); + } + + if ($canDo->get('core.edit.state')) + { + if ($this->state->get('filter.state') != 2) + { + JToolbarHelper::publish('banners.publish', 'JTOOLBAR_PUBLISH', true); + JToolbarHelper::unpublish('banners.unpublish', 'JTOOLBAR_UNPUBLISH', true); + } + + if ($this->state->get('filter.state') != -1) + { + if ($this->state->get('filter.state') != 2) + { + JToolbarHelper::archiveList('banners.archive'); + } + elseif ($this->state->get('filter.state') == 2) + { + JToolbarHelper::unarchiveList('banners.publish'); + } + } + } + + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::checkin('banners.checkin'); + } + + if ($this->state->get('filter.state') == -2 && $canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'banners.delete', 'JTOOLBAR_EMPTY_TRASH'); + } + elseif ($canDo->get('core.edit.state')) + { + JToolbarHelper::trash('banners.trash'); + } + + // Add a batch button + if ($user->authorise('core.create', 'com_banners') && $user->authorise('core.edit', 'com_banners') && $user->authorise('core.edit.state', 'com_banners')) + { + JHtml::_('bootstrap.modal', 'collapseModal'); + $title = JText::_('JTOOLBAR_BATCH'); + + // Instantiate a new JLayoutFile instance and render the batch button + $layout = new JLayoutFile('joomla.toolbar.batch'); + + $dhtml = $layout->render(array('title' => $title)); + $bar->appendButton('Custom', $dhtml, 'batch'); + } + + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_banners'); + } + JToolbarHelper::help('JHELP_COMPONENTS_BANNERS_BANNERS'); + + JHtmlSidebar::setAction('index.php?option=com_banners&view=banners'); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_state', + JHtml::_('select.options', JHtml::_('jgrid.publishedOptions'), 'value', 'text', $this->state->get('filter.state'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('COM_BANNERS_SELECT_CLIENT'), + 'filter_client_id', + JHtml::_('select.options', BannersHelper::getClientOptions(), 'value', 'text', $this->state->get('filter.client_id')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_CATEGORY'), + 'filter_category_id', + JHtml::_('select.options', JHtml::_('category.options', 'com_banners'), 'value', 'text', $this->state->get('filter.category_id')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_LANGUAGE'), + 'filter_language', + JHtml::_('select.options', JHtml::_('contentlanguage.existing', true, true), 'value', 'text', $this->state->get('filter.language')) + ); + } + + /** + * Returns an array of fields the table can be sorted by + * + * @return array Array containing the field name to sort by as the key and display text as value + * + * @since 3.0 + */ + protected function getSortFields() + { + return array( + 'ordering' => JText::_('JGRID_HEADING_ORDERING'), + 'a.state' => JText::_('JSTATUS'), + 'a.name' => JText::_('COM_BANNERS_HEADING_NAME'), + 'a.sticky' => JText::_('COM_BANNERS_HEADING_STICKY'), + 'client_name' => JText::_('COM_BANNERS_HEADING_CLIENT'), + 'impmade' => JText::_('COM_BANNERS_HEADING_IMPRESSIONS'), + 'clicks' => JText::_('COM_BANNERS_HEADING_CLICKS'), + 'a.language' => JText::_('JGRID_HEADING_LANGUAGE'), + 'a.id' => JText::_('JGRID_HEADING_ID') + ); + } +} diff --git a/administrator/components/com_banners/views/client/index.html b/administrator/components/com_banners/views/client/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/views/client/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/client/tmpl/edit.php b/administrator/components/com_banners/views/client/tmpl/edit.php new file mode 100644 index 0000000..3396356 --- /dev/null +++ b/administrator/components/com_banners/views/client/tmpl/edit.php @@ -0,0 +1,139 @@ + + + +
+ + + + 'general')); ?> + item->id) ? JText::_('COM_BANNERS_NEW_CLIENT', true) : JText::sprintf('COM_BANNERS_EDIT_CLIENT', $this->item->id, true)); ?> +
+
+ get('core.edit.state')) : ?> +
+
+ form->getLabel('state'); ?> +
+
+ form->getInput('state'); ?> +
+
+ +
+
+ form->getLabel('name'); ?> +
+
+ form->getInput('name'); ?> +
+
+
+
+ form->getLabel('contact'); ?> +
+
+ form->getInput('contact'); ?> +
+
+
+
+ form->getLabel('email'); ?> +
+
+ form->getInput('email'); ?> +
+
+
+
+ form->getLabel('purchase_type'); ?> +
+
+ form->getInput('purchase_type'); ?> +
+
+
+
+ form->getLabel('track_impressions'); ?> +
+
+ form->getInput('track_impressions'); ?> +
+
+
+
+ form->getLabel('track_clicks'); ?> +
+
+ form->getInput('track_clicks'); ?> +
+
+
+
+ form->getLabel('id'); ?> +
+
+ form->getInput('id'); ?> +
+
+
+
+ form->getFieldset('extra') as $field) : ?> +
+ hidden) : ?> +
+ label; ?> +
+ +
+ input; ?> +
+
+ +
+
+ + + + form->getFieldset('metadata') as $field) : ?> +
+ hidden) : ?> +
+ label; ?> +
+ +
+ input; ?> +
+
+ + + + + + + +
diff --git a/administrator/components/com_banners/views/client/tmpl/index.html b/administrator/components/com_banners/views/client/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/views/client/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/client/view.html.php b/administrator/components/com_banners/views/client/view.html.php new file mode 100644 index 0000000..e11d740 --- /dev/null +++ b/administrator/components/com_banners/views/client/view.html.php @@ -0,0 +1,93 @@ +form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + JFactory::getApplication()->input->set('hidemainmenu', true); + + $user = JFactory::getUser(); + $isNew = ($this->item->id == 0); + $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $user->get('id')); + $canDo = BannersHelper::getActions(); + + JToolbarHelper::title($isNew ? JText::_('COM_BANNERS_MANAGER_CLIENT_NEW') : JText::_('COM_BANNERS_MANAGER_CLIENT_EDIT'), 'banners-clients.png'); + + // If not checked out, can save the item. + if (!$checkedOut && ($canDo->get('core.edit')||$canDo->get('core.create'))) + { + JToolbarHelper::apply('client.apply'); + JToolbarHelper::save('client.save'); + } + if (!$checkedOut && $canDo->get('core.create')) { + + JToolbarHelper::save2new('client.save2new'); + } + // If an existing item, can save to a copy. + if (!$isNew && $canDo->get('core.create')) + { + JToolbarHelper::save2copy('client.save2copy'); + } + + if (empty($this->item->id)) + { + JToolbarHelper::cancel('client.cancel'); + } + else + { + JToolbarHelper::cancel('client.cancel', 'JTOOLBAR_CLOSE'); + } + + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_COMPONENTS_BANNERS_CLIENTS_EDIT'); + } +} diff --git a/administrator/components/com_banners/views/clients/index.html b/administrator/components/com_banners/views/clients/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/views/clients/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/clients/tmpl/default.php b/administrator/components/com_banners/views/clients/tmpl/default.php new file mode 100644 index 0000000..169e477 --- /dev/null +++ b/administrator/components/com_banners/views/clients/tmpl/default.php @@ -0,0 +1,205 @@ +get('id'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$params = (isset($this->state->params)) ? $this->state->params : new JObject; +$archived = $this->state->get('filter.published') == 2 ? true : false; +$trashed = $this->state->get('filter.published') == -2 ? true : false; +$sortFields = $this->getSortFields(); +?> + +
+sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ +
+ +
+ + +
+
+ + pagination->getLimitBox(); ?> +
+
+ + +
+
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + items as $i => $item) : + $ordering = ($listOrder == 'ordering'); + $canCreate = $user->authorise('core.create', 'com_banners'); + $canEdit = $user->authorise('core.edit', 'com_banners'); + $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id') || $item->checked_out == 0; + $canChange = $user->authorise('core.edit.state', 'com_banners') && $canCheckin; + ?> + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ pagination->getListFooter(); ?> +
+ id); ?> + + state, $i, 'clients.', $canChange);?> + +
+ checked_out) : ?> + editor, $item->checked_out_time, 'clients.', $canCheckin); ?> + + + + escape($item->name); ?> + + escape($item->name); ?> + +
+
+ id, 'client.'); + JHtml::_('dropdown.divider'); + if ($item->state) : + JHtml::_('dropdown.unpublish', 'cb' . $i, 'clients.'); + else : + JHtml::_('dropdown.publish', 'cb' . $i, 'clients.'); + endif; + + JHtml::_('dropdown.divider'); + + if ($archived) : + JHtml::_('dropdown.unarchive', 'cb' . $i, 'clients.'); + else : + JHtml::_('dropdown.archive', 'cb' . $i, 'clients.'); + endif; + + if ($item->checked_out) : + JHtml::_('dropdown.checkin', 'cb' . $i, 'clients.'); + endif; + + if ($trashed) : + JHtml::_('dropdown.untrash', 'cb' . $i, 'clients.'); + else : + JHtml::_('dropdown.trash', 'cb' . $i, 'clients.'); + endif; + + // render dropdown list + echo JHtml::_('dropdown.render'); + ?> +
+
+ contact;?> + + nbanners; ?> + + purchase_type < 0):?> + get('purchase_type')));?> + + purchase_type);?> + + + id; ?> +
+ + + + + + +
+ diff --git a/administrator/components/com_banners/views/clients/tmpl/index.html b/administrator/components/com_banners/views/clients/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/views/clients/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/clients/view.html.php b/administrator/components/com_banners/views/clients/view.html.php new file mode 100644 index 0000000..92ded45 --- /dev/null +++ b/administrator/components/com_banners/views/clients/view.html.php @@ -0,0 +1,118 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + BannersHelper::addSubmenu('clients'); + + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + require_once JPATH_COMPONENT.'/helpers/banners.php'; + + $canDo = BannersHelper::getActions(); + + JToolbarHelper::title(JText::_('COM_BANNERS_MANAGER_CLIENTS'), 'banners-clients.png'); + if ($canDo->get('core.create')) + { + JToolbarHelper::addNew('client.add'); + } + if ($canDo->get('core.edit')) + { + JToolbarHelper::editList('client.edit'); + } + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::publish('clients.publish', 'JTOOLBAR_PUBLISH', true); + JToolbarHelper::unpublish('clients.unpublish', 'JTOOLBAR_UNPUBLISH', true); + JToolbarHelper::archiveList('clients.archive'); + JToolbarHelper::checkin('clients.checkin'); + } + if ($this->state->get('filter.state') == -2 && $canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'clients.delete', 'JTOOLBAR_EMPTY_TRASH'); + } elseif ($canDo->get('core.edit.state')) + { + JToolbarHelper::trash('clients.trash'); + } + + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_banners'); + } + + JToolbarHelper::help('JHELP_COMPONENTS_BANNERS_CLIENTS'); + + JHtmlSidebar::setAction('index.php?option=com_banners&view=clients'); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_state', + JHtml::_('select.options', JHtml::_('jgrid.publishedOptions'), 'value', 'text', $this->state->get('filter.state'), true) + ); + } + /** + * Returns an array of fields the table can be sorted by + * + * @return array Array containing the field name to sort by as the key and display text as value + * + * @since 3.0 + */ + protected function getSortFields() + { + return array( + 'a.status' => JText::_('JSTATUS'), + 'a.name' => JText::_('COM_BANNERS_HEADING_CLIENT'), + 'contact' => JText::_('COM_BANNERS_HEADING_CONTACT'), + 'client_name' => JText::_('COM_BANNERS_HEADING_CLIENT'), + 'nbanners' => JText::_('COM_BANNERS_HEADING_ACTIVE'), + 'a.id' => JText::_('JGRID_HEADING_ID') + ); + } +} diff --git a/administrator/components/com_banners/views/download/index.html b/administrator/components/com_banners/views/download/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/views/download/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/download/tmpl/default.php b/administrator/components/com_banners/views/download/tmpl/default.php new file mode 100644 index 0000000..27f2fe3 --- /dev/null +++ b/administrator/components/com_banners/views/download/tmpl/default.php @@ -0,0 +1,32 @@ + +
+
+ + + form->getFieldset() as $field) : ?> + hidden) : ?> + label; ?> + + input; ?> + +
+ + + +
+
diff --git a/administrator/components/com_banners/views/download/tmpl/index.html b/administrator/components/com_banners/views/download/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/views/download/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/download/view.html.php b/administrator/components/com_banners/views/download/view.html.php new file mode 100644 index 0000000..a6a7398 --- /dev/null +++ b/administrator/components/com_banners/views/download/view.html.php @@ -0,0 +1,38 @@ +form = $this->get('Form'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + parent::display($tpl); + } +} diff --git a/administrator/components/com_banners/views/index.html b/administrator/components/com_banners/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/tracks/index.html b/administrator/components/com_banners/views/tracks/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/views/tracks/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/tracks/tmpl/default.php b/administrator/components/com_banners/views/tracks/tmpl/default.php new file mode 100644 index 0000000..6b4de03 --- /dev/null +++ b/administrator/components/com_banners/views/tracks/tmpl/default.php @@ -0,0 +1,138 @@ +get('id'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$sortFields = $this->getSortFields(); +?> + +
+sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ +
+ + +
+ + pagination->getLimitBox(); ?> +
+
+ + +
+
+ + +
+
+
+ + + + + + + + + + + + + + + + + items as $i => $item) :?> + + + + + + + + + +
+ + + + + + + + + +
+ pagination->getListFooter(); ?> +
+ name;?> +
+ category_title;?> +
+
+ client_name;?> + + track_type == 1 ? JText::_('COM_BANNERS_IMPRESSION') : JText::_('COM_BANNERS_CLICK');?> + + count;?> + + track_date, JText::_('DATE_FORMAT_LC4').' H:i');?> +
+ + + + + + +
+ diff --git a/administrator/components/com_banners/views/tracks/tmpl/index.html b/administrator/components/com_banners/views/tracks/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_banners/views/tracks/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_banners/views/tracks/view.html.php b/administrator/components/com_banners/views/tracks/view.html.php new file mode 100644 index 0000000..6baa1b4 --- /dev/null +++ b/administrator/components/com_banners/views/tracks/view.html.php @@ -0,0 +1,116 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + BannersHelper::addSubmenu('tracks'); + + $this->addToolbar(); + require_once JPATH_COMPONENT .'/models/fields/bannerclient.php'; + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + require_once JPATH_COMPONENT.'/helpers/banners.php'; + + $canDo = BannersHelper::getActions($this->state->get('filter.category_id')); + + JToolbarHelper::title(JText::_('COM_BANNERS_MANAGER_TRACKS'), 'banners-tracks.png'); + + $bar = JToolBar::getInstance('toolbar'); + $bar->appendButton('Slider', 'export', 'JTOOLBAR_EXPORT', 'index.php?option=com_banners&view=download&tmpl=component', 600, 300); + if ($canDo->get('core.delete')) + { + $bar->appendButton('Confirm', 'COM_BANNERS_DELETE_MSG', 'delete', 'COM_BANNERS_TRACKS_DELETE', 'tracks.delete', false); + JToolbarHelper::divider(); + } + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_banners'); + JToolbarHelper::divider(); + } + JToolbarHelper::help('JHELP_COMPONENTS_BANNERS_TRACKS'); + + JHtmlSidebar::setAction('index.php?option=com_banners&view=tracks'); + + JHtmlSidebar::addFilter( + JText::_('COM_BANNERS_SELECT_CLIENT'), + 'filter_client_id', + JHtml::_('select.options', BannersHelper::getClientOptions(), 'value', 'text', $this->state->get('filter.client_id')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_CATEGORY'), + 'filter_category_id', + JHtml::_('select.options', JHtml::_('category.options', 'com_banners'), 'value', 'text', $this->state->get('filter.category_id')) + ); + + JHtmlSidebar::addFilter( + JText::_('COM_BANNERS_SELECT_TYPE'), + 'filter_type', + JHtml::_('select.options', array(JHtml::_('select.option', 1, JText::_('COM_BANNERS_IMPRESSION')), JHtml::_('select.option', 2, JText::_('COM_BANNERS_CLICK'))), 'value', 'text', $this->state->get('filter.type')) + ); + } + + /** + * Returns an array of fields the table can be sorted by + * + * @return array Array containing the field name to sort by as the key and display text as value + * + * @since 3.0 + */ + protected function getSortFields() + { + return array( + 'b.name' => JText::_('COM_BANNERS_HEADING_NAME'), + 'cl.name' => JText::_('COM_BANNERS_HEADING_CLIENT'), + 'track_type' => JText::_('COM_BANNERS_HEADING_TYPE'), + 'count' => JText::_('COM_BANNERS_HEADING_COUNT'), + 'track_date' => JText::_('JDATE') + ); + } +} diff --git a/administrator/components/com_banners/views/tracks/view.raw.php b/administrator/components/com_banners/views/tracks/view.raw.php new file mode 100644 index 0000000..e40705d --- /dev/null +++ b/administrator/components/com_banners/views/tracks/view.raw.php @@ -0,0 +1,43 @@ +get('BaseName'); + $filetype = $this->get('FileType'); + $mimetype = $this->get('MimeType'); + $content = $this->get('Content'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $document = JFactory::getDocument(); + $document->setMimeEncoding($mimetype); + JResponse::setHeader('Content-disposition', 'attachment; filename="'.$basename.'.'.$filetype.'"; creation-date="'.JFactory::getDate()->toRFC822().'"', true); + echo $content; + } +} diff --git a/administrator/components/com_cache/cache.php b/administrator/components/com_cache/cache.php new file mode 100644 index 0000000..873060e --- /dev/null +++ b/administrator/components/com_cache/cache.php @@ -0,0 +1,19 @@ +authorise('core.manage', 'com_cache')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$controller = JControllerLegacy::getInstance('Cache'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_cache/cache.xml b/administrator/components/com_cache/cache.xml new file mode 100644 index 0000000..135efc2 --- /dev/null +++ b/administrator/components/com_cache/cache.xml @@ -0,0 +1,28 @@ + + + com_cache + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_CACHE_XML_DESCRIPTION + + + + cache.php + config.xml + controller.php + index.html + models + views + + + language/en-GB.com_cache.ini + language/en-GB.com_cache.sys.ini + + + + diff --git a/administrator/components/com_cache/config.xml b/administrator/components/com_cache/config.xml new file mode 100644 index 0000000..fede1c8 --- /dev/null +++ b/administrator/components/com_cache/config.xml @@ -0,0 +1,27 @@ + + +
+ + + + + +
+
diff --git a/administrator/components/com_cache/controller.php b/administrator/components/com_cache/controller.php new file mode 100644 index 0000000..6d96cc9 --- /dev/null +++ b/administrator/components/com_cache/controller.php @@ -0,0 +1,106 @@ +input->get('view', 'cache'); + $vFormat = $document->getType(); + $lName = $this->input->get('layout', 'default'); + + // Get and render the view. + if ($view = $this->getView($vName, $vFormat)) + { + switch ($vName) + { + case 'purge': + break; + case 'cache': + default: + $model = $this->getModel($vName); + $view->setModel($model, true); + break; + } + + $view->setLayout($lName); + + // Push document object into the view. + $view->document = $document; + + // Load the submenu. + CacheHelper::addSubmenu($this->input->get('view', 'cache')); + + $view->display(); + } + } + + public function delete() + { + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JInvalid_Token')); + + $cid = $this->input->post->get('cid', array(), 'array'); + + $model = $this->getModel('cache'); + + if (empty($cid)) + { + JError::raiseWarning(500, JText::_('JERROR_NO_ITEMS_SELECTED')); + } + else + { + $model->cleanlist($cid); + } + + $this->setRedirect('index.php?option=com_cache&client='.$model->getClient()->id); + } + + public function purge() + { + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JInvalid_Token')); + + $model = $this->getModel('cache'); + $ret = $model->purge(); + + $msg = JText::_('COM_CACHE_EXPIRED_ITEMS_HAVE_BEEN_PURGED'); + $msgType = 'message'; + + if ($ret === false) + { + $msg = JText::_('COM_CACHE_EXPIRED_ITEMS_PURGING_ERROR'); + $msgType = 'error'; + } + + $this->setRedirect('index.php?option=com_cache&view=purge', $msg, $msgType); + } +} diff --git a/administrator/components/com_cache/helpers/cache.php b/administrator/components/com_cache/helpers/cache.php new file mode 100644 index 0000000..2fbd889 --- /dev/null +++ b/administrator/components/com_cache/helpers/cache.php @@ -0,0 +1,62 @@ + diff --git a/administrator/components/com_cache/index.html b/administrator/components/com_cache/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_cache/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_cache/models/cache.php b/administrator/components/com_cache/models/cache.php new file mode 100644 index 0000000..3216813 --- /dev/null +++ b/administrator/components/com_cache/models/cache.php @@ -0,0 +1,185 @@ +getUserStateFromRequest($this->context.'.filter.client_id', 'filter_client_id', 0, 'int'); + $this->setState('clientId', $clientId == 1 ? 1 : 0); + + $client = JApplicationHelper::getClientInfo($clientId); + $this->setState('client', $client); + + parent::populateState('group', 'asc'); + } + + /** + * Method to get cache data + * + * @return array + */ + public function getData() + { + if (empty($this->_data)) + { + $cache = $this->getCache(); + $data = $cache->getAll(); + + if ($data != false) + { + $this->_data = $data; + $this->_total = count($data); + + if ($this->_total) + { + // Apply custom ordering + $ordering = $this->getState('list.ordering'); + $direction = ($this->getState('list.direction') == 'asc') ? 1 : -1; + + jimport('joomla.utilities.arrayhelper'); + $this->_data = JArrayHelper::sortObjects($data, $ordering, $direction); + + // Apply custom pagination + if ($this->_total > $this->getState('list.limit') && $this->getState('list.limit')) + { + $this->_data = array_slice($this->_data, $this->getState('list.start'), $this->getState('list.limit')); + } + } + } else { + $this->_data = array(); + } + } + return $this->_data; + } + + /** + * Method to get cache instance + * + * @return object + */ + public function getCache() + { + $conf = JFactory::getConfig(); + + $options = array( + 'defaultgroup' => '', + 'storage' => $conf->get('cache_handler', ''), + 'caching' => true, + 'cachebase' => ($this->getState('clientId') == 1) ? JPATH_ADMINISTRATOR . '/cache' : $conf->get('cache_path', JPATH_SITE . '/cache') + ); + + $cache = JCache::getInstance('', $options); + + return $cache; + } + + /** + * Method to get client data + * + * @return array + */ + public function getClient() + { + return $this->getState('client'); + } + + /** + * Get the number of current Cache Groups + * + * @return int + */ + public function getTotal() + { + if (empty($this->_total)) + { + $this->_total = count($this->getData()); + } + + return $this->_total; + } + + /** + * Method to get a pagination object for the cache + * + * @return integer + */ + public function getPagination() + { + if (empty($this->_pagination)) + { + $this->_pagination = new JPagination($this->getTotal(), $this->getState('list.start'), $this->getState('list.limit')); + } + + return $this->_pagination; + } + + /** + * Clean out a cache group as named by param. + * If no param is passed clean all cache groups. + * + * @param String $group + */ + public function clean($group = '') + { + $cache = $this->getCache(); + $cache->clean($group); + } + + public function cleanlist($array) + { + foreach ($array as $group) + { + $this->clean($group); + } + } + + public function purge() + { + $cache = JFactory::getCache(''); + return $cache->gc(); + } +} diff --git a/administrator/components/com_cache/models/index.html b/administrator/components/com_cache/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_cache/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_cache/views/cache/index.html b/administrator/components/com_cache/views/cache/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_cache/views/cache/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_cache/views/cache/tmpl/default.php b/administrator/components/com_cache/views/cache/tmpl/default.php new file mode 100644 index 0000000..8359974 --- /dev/null +++ b/administrator/components/com_cache/views/cache/tmpl/default.php @@ -0,0 +1,80 @@ +escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +?> + +
+ sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ + + + + + + + + + + + + + + + + data as $folder => $item) : ?> + + + + + + + + +
+ + + + + + + +
+ pagination->getListFooter(); ?> +
+ + + group; ?> + + count; ?> + + size*1024); ?> +
+ + + + + + + +
+ diff --git a/administrator/components/com_cache/views/cache/tmpl/index.html b/administrator/components/com_cache/views/cache/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_cache/views/cache/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_cache/views/cache/view.html.php b/administrator/components/com_cache/views/cache/view.html.php new file mode 100644 index 0000000..6ff7657 --- /dev/null +++ b/administrator/components/com_cache/views/cache/view.html.php @@ -0,0 +1,71 @@ +data = $this->get('Data'); + $this->client = $this->get('Client'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + JToolbarHelper::title(JText::_('COM_CACHE_CLEAR_CACHE'), 'clear.png'); + JToolbarHelper::custom('delete', 'delete.png', 'delete_f2.png', 'JTOOLBAR_DELETE', true); + JToolbarHelper::divider(); + if (JFactory::getUser()->authorise('core.admin', 'com_cache')) + { + JToolbarHelper::preferences('com_cache'); + } + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_SITE_MAINTENANCE_CLEAR_CACHE'); + + JHtmlSidebar::setAction('index.php?option=com_cache'); + + JHtmlSidebar::addFilter( + // @todo We need an actual label here + '', + 'filter_client_id', + JHtml::_('select.options', CacheHelper::getClientOptions(), 'value', 'text', $this->state->get('clientId')) + ); + } +} diff --git a/administrator/components/com_cache/views/index.html b/administrator/components/com_cache/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_cache/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_cache/views/purge/index.html b/administrator/components/com_cache/views/purge/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_cache/views/purge/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_cache/views/purge/tmpl/default.php b/administrator/components/com_cache/views/purge/tmpl/default.php new file mode 100644 index 0000000..6103098 --- /dev/null +++ b/administrator/components/com_cache/views/purge/tmpl/default.php @@ -0,0 +1,32 @@ + + +
+ sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ +
+ +

+
+
+

+
+ + +
+ diff --git a/administrator/components/com_cache/views/purge/tmpl/index.html b/administrator/components/com_cache/views/purge/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_cache/views/purge/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_cache/views/purge/view.html.php b/administrator/components/com_cache/views/purge/view.html.php new file mode 100644 index 0000000..22d83e1 --- /dev/null +++ b/administrator/components/com_cache/views/purge/view.html.php @@ -0,0 +1,47 @@ +addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + //JHtmlSidebar::addEntry(JText::_('COM_CACHE_BACK_CACHE_MANAGER'), 'index.php?option=com_cache', false); + + JToolbarHelper::title(JText::_('COM_CACHE_PURGE_EXPIRED_CACHE'), 'purge.png'); + JToolbarHelper::custom('purge', 'delete.png', 'delete_f2.png', 'COM_CACHE_PURGE_EXPIRED', false); + JToolbarHelper::divider(); + if (JFactory::getUser()->authorise('core.admin', 'com_cache')) + { + JToolbarHelper::preferences('com_cache'); + JToolbarHelper::divider(); + } + JToolbarHelper::help('JHELP_SITE_MAINTENANCE_PURGE_EXPIRED_CACHE'); + } +} diff --git a/administrator/components/com_categories/categories.php b/administrator/components/com_categories/categories.php new file mode 100644 index 0000000..c540e37 --- /dev/null +++ b/administrator/components/com_categories/categories.php @@ -0,0 +1,25 @@ +input; + +if (!JFactory::getUser()->authorise('core.manage', $input->get('extension'))) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +JLoader::register('JHtmlCategoriesAdministrator', JPATH_ADMINISTRATOR . '/components/com_categories/helpers/html/categoriesadministrator.php'); + +$task = $input->get('task'); + +$controller = JControllerLegacy::getInstance('Categories'); +$controller->execute($input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_categories/categories.xml b/administrator/components/com_categories/categories.xml new file mode 100644 index 0000000..166fb1d --- /dev/null +++ b/administrator/components/com_categories/categories.xml @@ -0,0 +1,30 @@ + + + com_categories + Joomla! Project + December 2007 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL + admin@joomla.org + www.joomla.org + 3.0.0 + COM_CATEGORIES_XML_DESCRIPTION + + + categories.php + config.xml + controller.php + index.html + controllers + helpers + models + views + + + language/en-GB.com_categories.ini + language/en-GB.com_categories.sys.ini + + + + + diff --git a/administrator/components/com_categories/controller.php b/administrator/components/com_categories/controller.php new file mode 100644 index 0000000..2ee0f40 --- /dev/null +++ b/administrator/components/com_categories/controller.php @@ -0,0 +1,100 @@ +extension)) + { + $this->extension = $this->input->get('extension', 'com_content'); + } + } + + /** + * Method to display a view. + * + * @param boolean $cachable If true, the view output will be cached + * @param array $urlparams An array of safe url parameters and their variable types, for valid values see {@link JFilterInput::clean()}. + * + * @return JController This object to support chaining. + * + * @since 1.5 + */ + public function display($cachable = false, $urlparams = false) + { + // Get the document object. + $document = JFactory::getDocument(); + + // Set the default view name and format from the Request. + $vName = $this->input->get('view', 'categories'); + $vFormat = $document->getType(); + $lName = $this->input->get('layout', 'default'); + $id = $this->input->getInt('id'); + + // Check for edit form. + if ($vName == 'category' && $lName == 'edit' && !$this->checkEditId('com_categories.edit.category', $id)) + { + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_categories&view=categories&extension=' . $this->extension, false)); + + return false; + } + + // Get and render the view. + if ($view = $this->getView($vName, $vFormat)) + { + // Get the model for the view. + $model = $this->getModel($vName, 'CategoriesModel', array('name' => $vName . '.' . substr($this->extension, 4))); + + // Push the model into the view (as default). + $view->setModel($model, true); + $view->setLayout($lName); + + // Push document object into the view. + $view->document = $document; + + // Load the submenu. + require_once JPATH_COMPONENT . '/helpers/categories.php'; + + CategoriesHelper::addSubmenu($model->getState('filter.extension')); + $view->display(); + } + + return $this; + } +} diff --git a/administrator/components/com_categories/controllers/categories.php b/administrator/components/com_categories/controllers/categories.php new file mode 100644 index 0000000..bbadf22 --- /dev/null +++ b/administrator/components/com_categories/controllers/categories.php @@ -0,0 +1,136 @@ + true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } + + /** + * Rebuild the nested set tree. + * + * @return bool False on failure or error, true on success. + * + * @since 1.6 + */ + public function rebuild() + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $extension = $this->input->get('extension'); + $this->setRedirect(JRoute::_('index.php?option=com_categories&view=categories&extension=' . $extension, false)); + + $model = $this->getModel(); + + if ($model->rebuild()) + { + // Rebuild succeeded. + $this->setMessage(JText::_('COM_CATEGORIES_REBUILD_SUCCESS')); + return true; + } + else + { + // Rebuild failed. + $this->setMessage(JText::_('COM_CATEGORIES_REBUILD_FAILURE')); + return false; + } + } + + /** + * Save the manual order inputs from the categories list page. + * + * @return void + * + * @since 1.6 + */ + public function saveorder() + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Get the arrays from the Request + $order = $this->input->post->get('order', null, 'array'); + $originalOrder = explode(',', $this->input->getString('original_order_values')); + + // Make sure something has changed + if (!($order === $originalOrder)) + { + parent::saveorder(); + } + else + { + // Nothing to reorder + $this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_list, false)); + return true; + } + } + + /** + * Deletes and returns correctly. + * + * @return void + * + * @since 3.1.2 + */ + public function delete() + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Get items to remove from the request. + $cid = $this->input->get('cid', array(), 'array'); + $extension = $this->input->getCmd('extension', null); + + if (!is_array($cid) || count($cid) < 1) + { + JError::raiseWarning(500, JText::_($this->text_prefix . '_NO_ITEM_SELECTED')); + } + else + { + // Get the model. + $model = $this->getModel(); + + // Make sure the item ids are integers + jimport('joomla.utilities.arrayhelper'); + JArrayHelper::toInteger($cid); + + // Remove the items. + if ($model->delete($cid)) + { + $this->setMessage(JText::plural($this->text_prefix . '_N_ITEMS_DELETED', count($cid))); + } + else + { + $this->setMessage($model->getError()); + } + } + + $this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&extension=' . $extension, false)); + } +} diff --git a/administrator/components/com_categories/controllers/category.php b/administrator/components/com_categories/controllers/category.php new file mode 100644 index 0000000..de60de7 --- /dev/null +++ b/administrator/components/com_categories/controllers/category.php @@ -0,0 +1,202 @@ +extension)) + { + $this->extension = $this->input->get('extension', 'com_content'); + } + } + + /** + * Method to check if you can add a new record. + * + * @param array $data An array of input data. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowAdd($data = array()) + { + $user = JFactory::getUser(); + return ($user->authorise('core.create', $this->extension) || count($user->getAuthorisedCategories($this->extension, 'core.create'))); + } + + /** + * Method to check if you can edit a record. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowEdit($data = array(), $key = 'parent_id') + { + $recordId = (int) isset($data[$key]) ? $data[$key] : 0; + $user = JFactory::getUser(); + $userId = $user->get('id'); + + // Check general edit permission first. + if ($user->authorise('core.edit', $this->extension)) + { + return true; + } + + // Check specific edit permission. + if ($user->authorise('core.edit', $this->extension . '.category.' . $recordId)) + { + return true; + } + + // Fallback on edit.own. + // First test if the permission is available. + if ($user->authorise('core.edit.own', $this->extension . '.category.' . $recordId) || $user->authorise('core.edit.own', $this->extension)) + { + // Now test the owner is the user. + $ownerId = (int) isset($data['created_user_id']) ? $data['created_user_id'] : 0; + if (empty($ownerId) && $recordId) + { + // Need to do a lookup from the model. + $record = $this->getModel()->getItem($recordId); + + if (empty($record)) + { + return false; + } + + $ownerId = $record->created_user_id; + } + + // If the owner matches 'me' then do the test. + if ($ownerId == $userId) + { + return true; + } + } + return false; + } + + /** + * Method to run batch operations. + * + * @param object $model The model. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 1.6 + */ + public function batch($model = null) + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Set the model + $model = $this->getModel('Category'); + + // Preset the redirect + $this->setRedirect('index.php?option=com_categories&view=categories&extension=' . $this->extension); + + return parent::batch($model); + } + + /** + * Gets the URL arguments to append to an item redirect. + * + * @param integer $recordId The primary key id for the item. + * @param string $urlVar The name of the URL variable for the id. + * + * @return string The arguments to append to the redirect URL. + * + * @since 1.6 + */ + protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id') + { + $append = parent::getRedirectToItemAppend($recordId); + $append .= '&extension=' . $this->extension; + + return $append; + } + + /** + * Gets the URL arguments to append to a list redirect. + * + * @return string The arguments to append to the redirect URL. + * + * @since 1.6 + */ + protected function getRedirectToListAppend() + { + $append = parent::getRedirectToListAppend(); + $append .= '&extension=' . $this->extension; + + return $append; + } + + /** + * Function that allows child controller access to model data after the data has been saved. + * + * @param JModelLegacy $model The data model object. + * @param array $validData The validated data. + * + * @return void + * + * @since 3.1 + */ + protected function postSaveHook(JModelLegacy $model, $validData = array()) + { + $item = $model->getItem(); + + if (isset($item->params) && is_array($item->params)) + { + $registry = new JRegistry; + $registry->loadArray($item->params); + $item->params = (string) $registry; + } + if (isset($item->metadata) && is_array($item->metadata)) + { + $registry = new JRegistry; + $registry->loadArray($item->metadata); + $item->metadata = (string) $registry; + } + + return; + } +} diff --git a/administrator/components/com_categories/controllers/index.html b/administrator/components/com_categories/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_categories/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_categories/helpers/association.php b/administrator/components/com_categories/helpers/association.php new file mode 100644 index 0000000..3b08a06 --- /dev/null +++ b/administrator/components/com_categories/helpers/association.php @@ -0,0 +1,62 @@ + $item) + { + if (class_exists($helperClassname) && is_callable(array($helperClassname, 'getCategoryRoute'))) + { + $return[$tag] = $helperClassname::getCategoryRoute($item, $tag); + } + else + { + $return[$tag] = 'index.php?option=' . $extension . '&view=category&id=' . $item; + } + } + } + + return $return; + } +} diff --git a/administrator/components/com_categories/helpers/categories.php b/administrator/components/com_categories/helpers/categories.php new file mode 100644 index 0000000..ffe8116 --- /dev/null +++ b/administrator/components/com_categories/helpers/categories.php @@ -0,0 +1,152 @@ + 1) + { + $section = $parts[1]; + } + + // Try to find the component helper. + $eName = str_replace('com_', '', $component); + $file = JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $component . '/helpers/' . $eName . '.php'); + + if (file_exists($file)) + { + require_once $file; + + $prefix = ucfirst(str_replace('com_', '', $component)); + $cName = $prefix . 'Helper'; + + if (class_exists($cName)) + { + + if (is_callable(array($cName, 'addSubmenu'))) + { + $lang = JFactory::getLanguage(); + // loading language file from the administrator/language directory then + // loading language file from the administrator/components/*extension*/language directory + $lang->load($component, JPATH_BASE, null, false, false) + || $lang->load($component, JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $component), null, false, false) + || $lang->load($component, JPATH_BASE, $lang->getDefault(), false, false) + || $lang->load($component, JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $component), $lang->getDefault(), false, false); + + call_user_func(array($cName, 'addSubmenu'), 'categories' . (isset($section) ? '.' . $section : '')); + } + } + } + } + + /** + * Gets a list of the actions that can be performed. + * + * @param string $extension The extension. + * @param integer $categoryId The category ID. + * + * @return JObject + * + * @since 1.6 + */ + public static function getActions($extension, $categoryId = 0) + { + $user = JFactory::getUser(); + $result = new JObject; + $parts = explode('.', $extension); + $component = $parts[0]; + + if (empty($categoryId)) + { + $assetName = $component; + $level = 'component'; + } + else + { + $assetName = $component . '.category.' . (int) $categoryId; + $level = 'category'; + } + + $actions = JAccess::getActions($component, $level); + + foreach ($actions as $action) + { + $result->set($action->name, $user->authorise($action->name, $assetName)); + } + + return $result; + } + + public static function getAssociations($pk, $extension = 'com_content') + { + $associations = array(); + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->from('#__categories as c') + ->join('INNER', '#__associations as a ON a.id = c.id AND a.context=' . $db->quote('com_categories.item')) + ->join('INNER', '#__associations as a2 ON a.key = a2.key') + ->join('INNER', '#__categories as c2 ON a2.id = c2.id AND c2.extension = ' . $db->quote($extension)) + ->where('c.id =' . (int) $pk) + ->where('c.extension = ' . $db->quote($extension)); + $select = array( + 'c2.language', + $query->concatenate(array('c2.id', 'c2.alias'), ':') . ' AS id' + ); + $query->select($select); + $db->setQuery($query); + $contentitems = $db->loadObjectList('language'); + + // Check for a database error. + if ($error = $db->getErrorMsg()) + { + JError::raiseWarning(500, $error); + return false; + } + + foreach ($contentitems as $tag => $item) + { + // Do not return itself as result + if ((int) $item->id != $pk) + { + $associations[$tag] = $item->id; + } + } + + return $associations; + } +} diff --git a/administrator/components/com_categories/helpers/html/categoriesadministrator.php b/administrator/components/com_categories/helpers/html/categoriesadministrator.php new file mode 100644 index 0000000..809c545 --- /dev/null +++ b/administrator/components/com_categories/helpers/html/categoriesadministrator.php @@ -0,0 +1,84 @@ +getQuery(true) + ->select('c.id, c.title') + ->select('l.sef as lang_sef') + ->from('#__categories as c') + ->where('c.id IN (' . implode(',', array_values($associations)) . ')') + ->join('LEFT', '#__languages as l ON c.language=l.lang_code') + ->select('l.image') + ->select('l.title as language_title'); + $db->setQuery($query); + + try + { + $items = $db->loadObjectList('id'); + } + catch (RuntimeException $e) + { + throw new Exception($e->getMessage(), 500); + } + + if ($items) + { + foreach ($items as &$item) + { + $text = strtoupper($item->lang_sef); + $url = JRoute::_('index.php?option=com_categories&task=category.edit&id=' . (int) $item->id . '&extension=' . $extension); + $tooltipParts = array( + JHtml::_( + 'image', 'mod_languages/' . $item->image . '.gif', + $item->language_title, + array('title' => $item->language_title), + true + ), + $item->title + ); + + $item->link = JHtml::_('tooltip', implode(' ', $tooltipParts), null, null, $text, $url, null, 'hasTooltip label label-association label-' . $item->lang_sef); + } + } + + $html = JLayoutHelper::render('joomla.content.associations', $items); + } + + return $html; + } +} diff --git a/administrator/components/com_categories/helpers/html/index.html b/administrator/components/com_categories/helpers/html/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_categories/helpers/html/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_categories/helpers/index.html b/administrator/components/com_categories/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_categories/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_categories/index.html b/administrator/components/com_categories/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_categories/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_categories/models/categories.php b/administrator/components/com_categories/models/categories.php new file mode 100644 index 0000000..2cf686c --- /dev/null +++ b/administrator/components/com_categories/models/categories.php @@ -0,0 +1,315 @@ +context; + + $extension = $app->getUserStateFromRequest('com_categories.categories.filter.extension', 'extension', 'com_content', 'cmd'); + + $this->setState('filter.extension', $extension); + $parts = explode('.', $extension); + + // Extract the component name + $this->setState('filter.component', $parts[0]); + + // Extract the optional section name + $this->setState('filter.section', (count($parts) > 1) ? $parts[1] : null); + + $search = $this->getUserStateFromRequest($context . '.search', 'filter_search'); + $this->setState('filter.search', $search); + + $level = $this->getUserStateFromRequest($context . '.filter.level', 'filter_level', 0, 'int'); + $this->setState('filter.level', $level); + + $access = $this->getUserStateFromRequest($context . '.filter.access', 'filter_access', 0, 'int'); + $this->setState('filter.access', $access); + + $published = $this->getUserStateFromRequest($context . '.filter.published', 'filter_published', ''); + $this->setState('filter.published', $published); + + $language = $this->getUserStateFromRequest($context . '.filter.language', 'filter_language', ''); + $this->setState('filter.language', $language); + + // Force a language + $forcedLanguage = $app->input->get('forcedLanguage'); + if (!empty($forcedLanguage)) + { + $this->setState('filter.language', $forcedLanguage); + $this->setState('filter.forcedLanguage', $forcedLanguage); + } + + $tag = $this->getUserStateFromRequest($this->context . '.filter.tag', 'filter_tag', ''); + $this->setState('filter.tag', $tag); + + // List state information. + parent::populateState('a.lft', 'asc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + * + * @since 1.6 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.extension'); + $id .= ':' . $this->getState('filter.published'); + $id .= ':' . $this->getState('filter.language'); + + return parent::getStoreId($id); + } + + /** + * @return string + * + * @since 1.6 + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + $user = JFactory::getUser(); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.id, a.title, a.alias, a.note, a.published, a.access' . + ', a.checked_out, a.checked_out_time, a.created_user_id' . + ', a.path, a.parent_id, a.level, a.lft, a.rgt' . + ', a.language' + ) + ); + $query->from('#__categories AS a'); + + // Join over the language + $query->select('l.title AS language_title') + ->join('LEFT', $db->quoteName('#__languages') . ' AS l ON l.lang_code = a.language'); + + // Join over the users for the checked out user. + $query->select('uc.name AS editor') + ->join('LEFT', '#__users AS uc ON uc.id=a.checked_out'); + + // Join over the asset groups. + $query->select('ag.title AS access_level') + ->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access'); + + // Join over the users for the author. + $query->select('ua.name AS author_name') + ->join('LEFT', '#__users AS ua ON ua.id = a.created_user_id'); + + // Join over the associations. + $assoc = $this->getAssoc(); + if ($assoc) + { + $query->select('COUNT(asso2.id)>1 as association') + ->join('LEFT', '#__associations AS asso ON asso.id = a.id AND asso.context=' . $db->quote('com_categories.item')) + ->join('LEFT', '#__associations AS asso2 ON asso2.key = asso.key') + ->group('a.id'); + } + + // Filter by extension + if ($extension = $this->getState('filter.extension')) + { + $query->where('a.extension = ' . $db->quote($extension)); + } + + // Filter on the level. + if ($level = $this->getState('filter.level')) + { + $query->where('a.level <= ' . (int) $level); + } + + // Filter by access level. + if ($access = $this->getState('filter.access')) + { + $query->where('a.access = ' . (int) $access); + } + + // Implement View Level Access + if (!$user->authorise('core.admin')) + { + $groups = implode(',', $user->getAuthorisedViewLevels()); + $query->where('a.access IN (' . $groups . ')'); + } + + // Filter by published state + $published = $this->getState('filter.published'); + if (is_numeric($published)) + { + $query->where('a.published = ' . (int) $published); + } + elseif ($published === '') + { + $query->where('(a.published IN (0, 1))'); + } + + // Filter by search in title + $search = $this->getState('filter.search'); + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + elseif (stripos($search, 'author:') === 0) + { + $search = $db->quote('%' . $db->escape(substr($search, 7), true) . '%'); + $query->where('(ua.name LIKE ' . $search . ' OR ua.username LIKE ' . $search . ')'); + } + else + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('(a.title LIKE ' . $search . ' OR a.alias LIKE ' . $search . ' OR a.note LIKE ' . $search . ')'); + } + } + + // Filter on the language. + if ($language = $this->getState('filter.language')) + { + $query->where('a.language = ' . $db->quote($language)); + } + + // Filter by a single tag. + $tagId = $this->getState('filter.tag'); + if (is_numeric($tagId)) + { + $query->where($db->quoteName('tagmap.tag_id') . ' = ' . (int) $tagId) + ->join( + 'LEFT', $db->quoteName('#__contentitem_tag_map', 'tagmap') + . ' ON ' . $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id') + . ' AND ' . $db->quoteName('tagmap.type_alias') . ' = ' . $db->quote($extension . '.category') + ); + } + + // Add the list ordering clause + $listOrdering = $this->getState('list.ordering', 'a.lft'); + $listDirn = $db->escape($this->getState('list.direction', 'ASC')); + if ($listOrdering == 'a.access') + { + $query->order('a.access ' . $listDirn . ', a.lft ' . $listDirn); + } + else + { + $query->order($db->escape($listOrdering) . ' ' . $listDirn); + } + + //echo nl2br(str_replace('#__','jos_',$query)); + return $query; + } + + /** + * Method to determine if an association exists + * + * @return boolean True if the association exists + * + * @since 3.0 + */ + + public function getAssoc() + { + static $assoc = null; + + if (!is_null($assoc)) + { + return $assoc; + } + + $app = JFactory::getApplication(); + $extension = $this->getState('filter.extension'); + + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + $extension = explode('.', $extension); + $component = array_shift($extension); + $cname = str_replace('com_', '', $component); + + if (!$assoc || !$component || !$cname) + { + $assoc = false; + } + else + { + $hname = $cname . 'HelperAssociation'; + JLoader::register($hname, JPATH_SITE . '/components/' . $component . '/helpers/association.php'); + + $assoc = class_exists($hname) && !empty($hname::$category_association); + } + + return $assoc; + } +} diff --git a/administrator/components/com_categories/models/category.php b/administrator/components/com_categories/models/category.php new file mode 100644 index 0000000..cf74ca8 --- /dev/null +++ b/administrator/components/com_categories/models/category.php @@ -0,0 +1,1111 @@ +id)) + { + if ($record->published != -2) + { + return; + } + $user = JFactory::getUser(); + + return $user->authorise('core.delete', $record->extension . '.category.' . (int) $record->id); + } + } + + /** + * Method to test whether a record can have its state changed. + * + * @param object $record A record object. + * + * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. + * + * @since 1.6 + */ + protected function canEditState($record) + { + $user = JFactory::getUser(); + + // Check for existing category. + if (!empty($record->id)) + { + return $user->authorise('core.edit.state', $record->extension . '.category.' . (int) $record->id); + } + // New category, so check against the parent. + elseif (!empty($record->parent_id)) + { + return $user->authorise('core.edit.state', $record->extension . '.category.' . (int) $record->parent_id); + } + // Default to component settings if neither category nor parent known. + else + { + return $user->authorise('core.edit.state', $record->extension); + } + } + + /** + * Method to get a table object, load it if necessary. + * + * @param string $type The table name. Optional. + * @param string $prefix The class prefix. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return JTable A JTable object + * + * @since 1.6 + */ + public function getTable($type = 'Category', $prefix = 'CategoriesTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @return void + * + * @since 1.6 + */ + protected function populateState() + { + $app = JFactory::getApplication('administrator'); + + $parentId = $app->input->getInt('parent_id'); + $this->setState('category.parent_id', $parentId); + + // Load the User state. + $pk = $app->input->getInt('id'); + $this->setState($this->getName() . '.id', $pk); + + $extension = $app->input->get('extension', 'com_content'); + $this->setState('category.extension', $extension); + $parts = explode('.', $extension); + + // Extract the component name + $this->setState('category.component', $parts[0]); + + // Extract the optional section name + $this->setState('category.section', (count($parts) > 1) ? $parts[1] : null); + + // Load the parameters. + $params = JComponentHelper::getParams('com_categories'); + $this->setState('params', $params); + } + + /** + * Method to get a category. + * + * @param integer $pk An optional id of the object to get, otherwise the id from the model state is used. + * + * @return mixed Category data object on success, false on failure. + * + * @since 1.6 + */ + public function getItem($pk = null) + { + if ($result = parent::getItem($pk)) + { + + // Prime required properties. + if (empty($result->id)) + { + $result->parent_id = $this->getState('category.parent_id'); + $result->extension = $this->getState('category.extension'); + } + + // Convert the metadata field to an array. + $registry = new JRegistry; + $registry->loadString($result->metadata); + $result->metadata = $registry->toArray(); + + // Convert the created and modified dates to local user time for display in the form. + $tz = new DateTimeZone(JFactory::getApplication()->getCfg('offset')); + + if ((int) $result->created_time) + { + $date = new JDate($result->created_time); + $date->setTimezone($tz); + $result->created_time = $date->toSql(true); + } + else + { + $result->created_time = null; + } + + if ((int) $result->modified_time) + { + $date = new JDate($result->modified_time); + $date->setTimezone($tz); + $result->modified_time = $date->toSql(true); + } + else + { + $result->modified_time = null; + } + + if (!empty($result->id)) + { + $result->tags = new JHelperTags; + $result->tags->getTagIds($result->id, $result->extension . '.category'); + } + } + + $assoc = $this->getAssoc(); + if ($assoc) + { + if ($result->id != null) + { + $result->associations = CategoriesHelper::getAssociations($result->id, $result->extension); + JArrayHelper::toInteger($result->associations); + } + else + { + $result->associations = array(); + } + } + + return $result; + } + + /** + * Method to get the row form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * + * @return mixed A JForm object on success, false on failure + * + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + $extension = $this->getState('category.extension'); + $jinput = JFactory::getApplication()->input; + + // A workaround to get the extension into the model for save requests. + if (empty($extension) && isset($data['extension'])) + { + $extension = $data['extension']; + $parts = explode('.', $extension); + + $this->setState('category.extension', $extension); + $this->setState('category.component', $parts[0]); + $this->setState('category.section', @$parts[1]); + } + + // Get the form. + $form = $this->loadForm('com_categories.category' . $extension, 'category', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + // Modify the form based on Edit State access controls. + if (empty($data['extension'])) + { + $data['extension'] = $extension; + } + $user = JFactory::getUser(); + if (!$user->authorise('core.edit.state', $extension . '.category.' . $jinput->get('id'))) + { + // Disable fields for display. + $form->setFieldAttribute('ordering', 'disabled', 'true'); + $form->setFieldAttribute('published', 'disabled', 'true'); + + // Disable fields while saving. + // The controller has already verified this is a record you can edit. + $form->setFieldAttribute('ordering', 'filter', 'unset'); + $form->setFieldAttribute('published', 'filter', 'unset'); + } + + return $form; + } + + /** + * A protected method to get the where clause for the reorder + * This ensures that the row will be moved relative to a row with the same extension + * + * @param JCategoryTable $table Current table instance + * + * @return array An array of conditions to add to add to ordering queries. + * + * @since 1.6 + */ + protected function getReorderConditions($table) + { + return 'extension = ' . $this->_db->quote($table->extension); + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_categories.edit.' . $this->getName() . '.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + } + + $this->preprocessData('com_categories.category', $data); + + return $data; + } + + /** + * Method to preprocess the form. + * + * @param JForm $form A JForm object. + * @param mixed $data The data expected for the form. + * @param string $group The name of the plugin group to import. + * + * @return void + * + * @see JFormField + * @since 1.6 + * @throws Exception if there is an error in the form event. + */ + protected function preprocessForm(JForm $form, $data, $group = 'content') + { + jimport('joomla.filesystem.path'); + + $lang = JFactory::getLanguage(); + $component = $this->getState('category.component'); + $section = $this->getState('category.section'); + $extension = JFactory::getApplication()->input->get('extension', null); + + // Get the component form if it exists + $name = 'category' . ($section ? ('.' . $section) : ''); + + // Looking first in the component models/forms folder + $path = JPath::clean(JPATH_ADMINISTRATOR . "/components/$component/models/forms/$name.xml"); + + // Old way: looking in the component folder + if (!file_exists($path)) + { + $path = JPath::clean(JPATH_ADMINISTRATOR . "/components/$component/$name.xml"); + } + + if (file_exists($path)) + { + $lang->load($component, JPATH_BASE, null, false, false); + $lang->load($component, JPATH_BASE, $lang->getDefault(), false, false); + $lang->load($component, JPATH_BASE . '/components/' . $component, null, false, false); + $lang->load($component, JPATH_BASE . '/components/' . $component, $lang->getDefault(), false, false); + + if (!$form->loadFile($path, false)) + { + throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); + } + } + + // Try to find the component helper. + $eName = str_replace('com_', '', $component); + $path = JPath::clean(JPATH_ADMINISTRATOR . "/components/$component/helpers/category.php"); + + if (file_exists($path)) + { + require_once $path; + $cName = ucfirst($eName) . ucfirst($section) . 'HelperCategory'; + + if (class_exists($cName) && is_callable(array($cName, 'onPrepareForm'))) + { + $lang->load($component, JPATH_BASE, null, false, false) || $lang->load($component, JPATH_BASE . '/components/' . $component, null, false, false) || $lang->load($component, JPATH_BASE, $lang->getDefault(), false, false) || $lang->load($component, JPATH_BASE . '/components/' . $component, $lang->getDefault(), false, false); + call_user_func_array(array($cName, 'onPrepareForm'), array(&$form)); + + // Check for an error. + if ($form instanceof Exception) + { + $this->setError($form->getMessage()); + return false; + } + } + } + + // Set the access control rules field component value. + $form->setFieldAttribute('rules', 'component', $component); + $form->setFieldAttribute('rules', 'section', $name); + + // Association category items + $assoc = $this->getAssoc(); + if ($assoc) + { + $languages = JLanguageHelper::getLanguages('lang_code'); + + // Force to array (perhaps move to $this->loadFormData()) + $data = (array) $data; + + $addform = new SimpleXMLElement('
'); + $fields = $addform->addChild('fields'); + $fields->addAttribute('name', 'associations'); + $fieldset = $fields->addChild('fieldset'); + $fieldset->addAttribute('name', 'item_associations'); + $fieldset->addAttribute('description', 'COM_CATEGORIES_ITEM_ASSOCIATIONS_FIELDSET_DESC'); + $add = false; + foreach ($languages as $tag => $language) + { + if (empty($data['language']) || $tag != $data['language']) + { + $add = true; + $field = $fieldset->addChild('field'); + $field->addAttribute('name', $tag); + $field->addAttribute('type', 'modal_category'); + $field->addAttribute('language', $tag); + $field->addAttribute('label', $language->title); + $field->addAttribute('translate_label', 'false'); + $field->addAttribute('extension', $extension); + $field->addAttribute('edit', 'true'); + $field->addAttribute('clear', 'true'); + } + } + if ($add) + { + $form->load($addform, false); + } + } + + // Trigger the default form events. + parent::preprocessForm($form, $data, $group); + } + + /** + * Method to save the form data. + * + * @param array $data The form data. + * + * @return boolean True on success. + * + * @since 1.6 + */ + public function save($data) + { + $dispatcher = JEventDispatcher::getInstance(); + $table = $this->getTable(); + $input = JFactory::getApplication()->input; + $pk = (!empty($data['id'])) ? $data['id'] : (int) $this->getState($this->getName() . '.id'); + $isNew = true; + + if ((!empty($data['tags']) && $data['tags'][0] != '')) + { + $table->newTags = $data['tags']; + } + + // Include the content plugins for the on save events. + JPluginHelper::importPlugin('content'); + + // Load the row if saving an existing category. + if ($pk > 0) + { + $table->load($pk); + $isNew = false; + } + + // Set the new parent id if parent id not matched OR while New/Save as Copy . + if ($table->parent_id != $data['parent_id'] || $data['id'] == 0) + { + $table->setLocation($data['parent_id'], 'last-child'); + } + + // Alter the title for save as copy + if ($input->get('task') == 'save2copy') + { + list($title, $alias) = $this->generateNewTitle($data['parent_id'], $data['alias'], $data['title']); + $data['title'] = $title; + $data['alias'] = $alias; + $data['published'] = 0; + } + + // Bind the data. + if (!$table->bind($data)) + { + $this->setError($table->getError()); + return false; + } + + // Bind the rules. + if (isset($data['rules'])) + { + $rules = new JAccessRules($data['rules']); + $table->setRules($rules); + } + + // Check the data. + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // Trigger the onContentBeforeSave event. + $result = $dispatcher->trigger($this->event_before_save, array($this->option . '.' . $this->name, &$table, $isNew)); + if (in_array(false, $result, true)) + { + $this->setError($table->getError()); + return false; + } + + // Store the data. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + $assoc = $this->getAssoc(); + if ($assoc) + { + + // Adding self to the association + $associations = $data['associations']; + + foreach ($associations as $tag => $id) + { + if (empty($id)) + { + unset($associations[$tag]); + } + } + + // Detecting all item menus + $all_language = $table->language == '*'; + + if ($all_language && !empty($associations)) + { + JError::raiseNotice(403, JText::_('COM_CATEGORIES_ERROR_ALL_LANGUAGE_ASSOCIATED')); + } + + $associations[$table->language] = $table->id; + + // Deleting old association for these items + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->delete('#__associations') + ->where($db->quoteName('context') . ' = ' . $db->quote('com_categories.item')) + ->where($db->quoteName('id') . ' IN (' . implode(',', $associations) . ')'); + $db->setQuery($query); + $db->execute(); + + if ($error = $db->getErrorMsg()) + { + $this->setError($error); + return false; + } + + if (!$all_language && count($associations)) + { + // Adding new association for these items + $key = md5(json_encode($associations)); + $query->clear() + ->insert('#__associations'); + + foreach ($associations as $id) + { + $query->values($id . ',' . $db->quote('com_categories.item') . ',' . $db->quote($key)); + } + + $db->setQuery($query); + $db->execute(); + + if ($error = $db->getErrorMsg()) + { + $this->setError($error); + return false; + } + } + } + + // Trigger the onContentAfterSave event. + $dispatcher->trigger($this->event_after_save, array($this->option . '.' . $this->name, &$table, $isNew)); + + // Rebuild the path for the category: + if (!$table->rebuildPath($table->id)) + { + $this->setError($table->getError()); + return false; + } + + // Rebuild the paths of the category's children: + if (!$table->rebuild($table->id, $table->lft, $table->level, $table->path)) + { + $this->setError($table->getError()); + return false; + } + + $this->setState($this->getName() . '.id', $table->id); + + // Clear the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to change the published state of one or more records. + * + * @param array &$pks A list of the primary keys to change. + * @param integer $value The value of the published state. + * + * @return boolean True on success. + * + * @since 2.5 + */ + public function publish(&$pks, $value = 1) + { + if (parent::publish($pks, $value)) + { + $dispatcher = JEventDispatcher::getInstance(); + $extension = JFactory::getApplication()->input->get('extension'); + + // Include the content plugins for the change of category state event. + JPluginHelper::importPlugin('content'); + + // Trigger the onCategoryChangeState event. + $dispatcher->trigger('onCategoryChangeState', array($extension, $pks, $value)); + + return true; + } + } + + /** + * Method rebuild the entire nested set tree. + * + * @return boolean False on failure or error, true otherwise. + * + * @since 1.6 + */ + public function rebuild() + { + // Get an instance of the table object. + $table = $this->getTable(); + + if (!$table->rebuild()) + { + $this->setError($table->getError()); + return false; + } + + // Clear the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to save the reordered nested set tree. + * First we save the new order values in the lft values of the changed ids. + * Then we invoke the table rebuild to implement the new ordering. + * + * @param array $idArray An array of primary key ids. + * @param integer $lft_array The lft value + * + * @return boolean False on failure or error, True otherwise + * + * @since 1.6 + */ + public function saveorder($idArray = null, $lft_array = null) + { + // Get an instance of the table object. + $table = $this->getTable(); + + if (!$table->saveorder($idArray, $lft_array)) + { + $this->setError($table->getError()); + return false; + } + + // Clear the cache + $this->cleanCache(); + + return true; + } + + protected function batchTag($value, $pks, $contexts) + { + // Set the variables + $user = JFactory::getUser(); + $table = $this->getTable(); + + foreach ($pks as $pk) + { + if ($user->authorise('core.edit', $contexts[$pk])) + { + $table->reset(); + $table->load($pk); + $tags = array($value); + + /** + * @var JTableObserverTags $tagsObserver + */ + $tagsObserver = $table->getObserverOfClass('JTableObserverTags'); + $result = $tagsObserver->setNewTags($tags, false); + + if (!$result) + { + $this->setError($table->getError()); + + return false; + } + } + else + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT')); + + return false; + } + } + + // Clean the cache + $this->cleanCache(); + + return true; + } + + /** + * Batch copy categories to a new category. + * + * @param integer $value The new category. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return mixed An array of new IDs on success, boolean false on failure. + * + * @since 1.6 + */ + protected function batchCopy($value, $pks, $contexts) + { + // $value comes as {parent_id}.{extension} + $parts = explode('.', $value); + $parentId = (int) JArrayHelper::getValue($parts, 0, 1); + + $table = $this->getTable(); + $db = $this->getDbo(); + $user = JFactory::getUser(); + $extension = JFactory::getApplication()->input->get('extension', '', 'word'); + $i = 0; + + // Check that the parent exists + if ($parentId) + { + if (!$table->load($parentId)) + { + if ($error = $table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Non-fatal error + $this->setError(JText::_('JGLOBAL_BATCH_MOVE_PARENT_NOT_FOUND')); + $parentId = 0; + } + } + // Check that user has create permission for parent category + $canCreate = ($parentId == $table->getRootId()) ? $user->authorise('core.create', $extension) : $user->authorise('core.create', $extension . '.category.' . $parentId); + if (!$canCreate) + { + // Error since user cannot create in parent category + $this->setError(JText::_('COM_CATEGORIES_BATCH_CANNOT_CREATE')); + return false; + } + } + + // If the parent is 0, set it to the ID of the root item in the tree + if (empty($parentId)) + { + if (!$parentId = $table->getRootId()) + { + $this->setError($db->getErrorMsg()); + return false; + } + // Make sure we can create in root + elseif (!$user->authorise('core.create', $extension)) + { + $this->setError(JText::_('COM_CATEGORIES_BATCH_CANNOT_CREATE')); + return false; + } + } + + // We need to log the parent ID + $parents = array(); + + // Calculate the emergency stop count as a precaution against a runaway loop bug + $query = $db->getQuery(true) + ->select('COUNT(id)') + ->from($db->quoteName('#__categories')); + $db->setQuery($query); + + try + { + $count = $db->loadResult(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + // Parent exists so we let's proceed + while (!empty($pks) && $count > 0) + { + // Pop the first id off the stack + $pk = array_shift($pks); + + $table->reset(); + + // Check that the row actually exists + if (!$table->load($pk)) + { + if ($error = $table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Not fatal error + $this->setError(JText::sprintf('JGLOBAL_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + } + + // Copy is a bit tricky, because we also need to copy the children + $query->clear() + ->select('id') + ->from($db->quoteName('#__categories')) + ->where('lft > ' . (int) $table->lft) + ->where('rgt < ' . (int) $table->rgt); + $db->setQuery($query); + $childIds = $db->loadColumn(); + + // Add child ID's to the array only if they aren't already there. + foreach ($childIds as $childId) + { + if (!in_array($childId, $pks)) + { + array_push($pks, $childId); + } + } + + // Make a copy of the old ID and Parent ID + $oldId = $table->id; + $oldParentId = $table->parent_id; + + // Reset the id because we are making a copy. + $table->id = 0; + + // If we a copying children, the Old ID will turn up in the parents list + // otherwise it's a new top level item + $table->parent_id = isset($parents[$oldParentId]) ? $parents[$oldParentId] : $parentId; + + // Set the new location in the tree for the node. + $table->setLocation($table->parent_id, 'last-child'); + + // TODO: Deal with ordering? + // $table->ordering = 1; + $table->level = null; + $table->asset_id = null; + $table->lft = null; + $table->rgt = null; + + // Alter the title & alias + list($title, $alias) = $this->generateNewTitle($table->parent_id, $table->alias, $table->title); + $table->title = $title; + $table->alias = $alias; + + // Store the row. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Get the new item ID + $newId = $table->get('id'); + + // Add the new ID to the array + $newIds[$i] = $newId; + $i++; + + // Now we log the old 'parent' to the new 'parent' + $parents[$oldId] = $table->id; + $count--; + } + + // Rebuild the hierarchy. + if (!$table->rebuild()) + { + $this->setError($table->getError()); + return false; + } + + // Rebuild the tree path. + if (!$table->rebuildPath($table->id)) + { + $this->setError($table->getError()); + return false; + } + + return $newIds; + } + + /** + * Batch move categories to a new category. + * + * @param integer $value The new category ID. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return boolean True on success. + * + * @since 1.6 + */ + protected function batchMove($value, $pks, $contexts) + { + $parentId = (int) $value; + + $table = $this->getTable(); + $db = $this->getDbo(); + $query = $db->getQuery(true); + $user = JFactory::getUser(); + $extension = JFactory::getApplication()->input->get('extension', '', 'word'); + + // Check that the parent exists. + if ($parentId) + { + if (!$table->load($parentId)) + { + if ($error = $table->getError()) + { + // Fatal error + $this->setError($error); + + return false; + } + else + { + // Non-fatal error + $this->setError(JText::_('JGLOBAL_BATCH_MOVE_PARENT_NOT_FOUND')); + $parentId = 0; + } + } + // Check that user has create permission for parent category + $canCreate = ($parentId == $table->getRootId()) ? $user->authorise('core.create', $extension) : $user->authorise('core.create', $extension . '.category.' . $parentId); + if (!$canCreate) + { + // Error since user cannot create in parent category + $this->setError(JText::_('COM_CATEGORIES_BATCH_CANNOT_CREATE')); + return false; + } + + // Check that user has edit permission for every category being moved + // Note that the entire batch operation fails if any category lacks edit permission + foreach ($pks as $pk) + { + if (!$user->authorise('core.edit', $extension . '.category.' . $pk)) + { + // Error since user cannot edit this category + $this->setError(JText::_('COM_CATEGORIES_BATCH_CANNOT_EDIT')); + return false; + } + } + } + + // We are going to store all the children and just move the category + $children = array(); + + // Parent exists so we let's proceed + foreach ($pks as $pk) + { + // Check that the row actually exists + if (!$table->load($pk)) + { + if ($error = $table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Not fatal error + $this->setError(JText::sprintf('JGLOBAL_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + } + + // Set the new location in the tree for the node. + $table->setLocation($parentId, 'last-child'); + + // Check if we are moving to a different parent + if ($parentId != $table->parent_id) + { + // Add the child node ids to the children array. + $query->clear() + ->select('id') + ->from($db->quoteName('#__categories')) + ->where($db->quoteName('lft') . ' BETWEEN ' . (int) $table->lft . ' AND ' . (int) $table->rgt); + $db->setQuery($query); + + try + { + $children = array_merge($children, (array) $db->loadColumn()); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + } + + // Store the row. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Rebuild the tree path. + if (!$table->rebuildPath()) + { + $this->setError($table->getError()); + return false; + } + } + + // Process the child rows + if (!empty($children)) + { + // Remove any duplicates and sanitize ids. + $children = array_unique($children); + JArrayHelper::toInteger($children); + } + + return true; + } + + /** + * Custom clean the cache of com_content and content modules + * + * @since 1.6 + */ + protected function cleanCache($group = null, $client_id = 0) + { + $extension = JFactory::getApplication()->input->get('extension'); + switch ($extension) + { + case 'com_content': + parent::cleanCache('com_content'); + parent::cleanCache('mod_articles_archive'); + parent::cleanCache('mod_articles_categories'); + parent::cleanCache('mod_articles_category'); + parent::cleanCache('mod_articles_latest'); + parent::cleanCache('mod_articles_news'); + parent::cleanCache('mod_articles_popular'); + break; + default: + parent::cleanCache($extension); + break; + } + } + + /** + * Method to change the title & alias. + * + * @param integer $parent_id The id of the parent. + * @param string $alias The alias. + * @param string $title The title. + * + * @return array Contains the modified title and alias. + * + * @since 1.7 + */ + protected function generateNewTitle($parent_id, $alias, $title) + { + // Alter the title & alias + $table = $this->getTable(); + while ($table->load(array('alias' => $alias, 'parent_id' => $parent_id))) + { + $title = JString::increment($title); + $alias = JString::increment($alias, 'dash'); + } + + return array($title, $alias); + } + + public function getAssoc() + { + static $assoc = null; + + if (!is_null($assoc)) + { + return $assoc; + } + + $app = JFactory::getApplication(); + $extension = $this->getState('category.extension'); + + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + $extension = explode('.', $extension); + $component = array_shift($extension); + $cname = str_replace('com_', '', $component); + + if (!$assoc || !$component || !$cname) + { + $assoc = false; + } + else + { + $hname = $cname . 'HelperAssociation'; + JLoader::register($hname, JPATH_SITE . '/components/' . $component . '/helpers/association.php'); + + $assoc = class_exists($hname) && !empty($hname::$category_association); + } + + return $assoc; + } +} diff --git a/administrator/components/com_categories/models/fields/categoryedit.php b/administrator/components/com_categories/models/fields/categoryedit.php new file mode 100644 index 0000000..2b60b4b --- /dev/null +++ b/administrator/components/com_categories/models/fields/categoryedit.php @@ -0,0 +1,230 @@ +element['published'] ? $this->element['published'] : array(0, 1); + $name = (string) $this->element['name']; + + // Let's get the id for the current item, either category or content item. + $jinput = JFactory::getApplication()->input; + // Load the category options for a given extension. + + // For categories the old category is the category id or 0 for new category. + if ($this->element['parent'] || $jinput->get('option') == 'com_categories') + { + $oldCat = $jinput->get('id', 0); + $oldParent = $this->form->getValue($name, 0); + $extension = $this->element['extension'] ? (string) $this->element['extension'] : (string) $jinput->get('extension', 'com_content'); + } + else + // For items the old category is the category they are in when opened or 0 if new. + { + $oldCat = $this->form->getValue($name, 0); + $extension = $this->element['extension'] ? (string) $this->element['extension'] : (string) $jinput->get('option', 'com_content'); + } + + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('a.id AS value, a.title AS text, a.level, a.published') + ->from('#__categories AS a') + ->join('LEFT', $db->quoteName('#__categories') . ' AS b ON a.lft > b.lft AND a.rgt < b.rgt'); + + // Filter by the extension type + if ($this->element['parent'] == true || $jinput->get('option') == 'com_categories') + { + $query->where('(a.extension = ' . $db->quote($extension) . ' OR a.parent_id = 0)'); + } + else + { + $query->where('(a.extension = ' . $db->quote($extension) . ')'); + } + // If parent isn't explicitly stated but we are in com_categories assume we want parents + if ($oldCat != 0 && ($this->element['parent'] == true || $jinput->get('option') == 'com_categories')) + { + // Prevent parenting to children of this item. + // To rearrange parents and children move the children up, not the parents down. + $query->join('LEFT', $db->quoteName('#__categories') . ' AS p ON p.id = ' . (int) $oldCat) + ->where('NOT(a.lft >= p.lft AND a.rgt <= p.rgt)'); + + $rowQuery = $db->getQuery(true); + $rowQuery->select('a.id AS value, a.title AS text, a.level, a.parent_id') + ->from('#__categories AS a') + ->where('a.id = ' . (int) $oldCat); + $db->setQuery($rowQuery); + $row = $db->loadObject(); + } + + // Filter language + if (!empty($this->element['language'])) + { + + $query->where('a.language = ' . $db->quote($this->element['language'])); + } + + // Filter on the published state + + if (is_numeric($published)) + { + $query->where('a.published = ' . (int) $published); + } + elseif (is_array($published)) + { + JArrayHelper::toInteger($published); + $query->where('a.published IN (' . implode(',', $published) . ')'); + } + + $query->group('a.id, a.title, a.level, a.lft, a.rgt, a.extension, a.parent_id, a.published') + ->order('a.lft ASC'); + + // Get the options. + $db->setQuery($query); + + try + { + $options = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage); + } + + // Pad the option text with spaces using depth level as a multiplier. + for ($i = 0, $n = count($options); $i < $n; $i++) + { + // Translate ROOT + if ($this->element['parent'] == true || $jinput->get('option') == 'com_categories') + { + if ($options[$i]->level == 0) + { + $options[$i]->text = JText::_('JGLOBAL_ROOT_PARENT'); + } + } + if ($options[$i]->published == 1) + { + $options[$i]->text = str_repeat('- ', $options[$i]->level) . $options[$i]->text; + } + else + { + $options[$i]->text = str_repeat('- ', $options[$i]->level) . '[' . $options[$i]->text . ']'; + } + } + + // Get the current user object. + $user = JFactory::getUser(); + + // For new items we want a list of categories you are allowed to create in. + if ($oldCat == 0) + { + foreach ($options as $i => $option) + { + // To take save or create in a category you need to have create rights for that category + // unless the item is already in that category. + // Unset the option if the user isn't authorised for it. In this field assets are always categories. + if ($user->authorise('core.create', $extension . '.category.' . $option->value) != true) + { + unset($options[$i]); + } + } + } + // If you have an existing category id things are more complex. + else + { + // If you are only allowed to edit in this category but not edit.state, you should not get any + // option to change the category parent for a category or the category for a content item, + // but you should be able to save in that category. + foreach ($options as $i => $option) + { + if ($user->authorise('core.edit.state', $extension . '.category.' . $oldCat) != true && !isset($oldParent)) + { + if ($option->value != $oldCat) + { + unset($options[$i]); + } + } + if ($user->authorise('core.edit.state', $extension . '.category.' . $oldCat) != true + && (isset($oldParent)) + && $option->value != $oldParent + ) + { + unset($options[$i]); + } + + // However, if you can edit.state you can also move this to another category for which you have + // create permission and you should also still be able to save in the current category. + if (($user->authorise('core.create', $extension . '.category.' . $option->value) != true) + && ($option->value != $oldCat && !isset($oldParent)) + ) + { + { + unset($options[$i]); + } + } + if (($user->authorise('core.create', $extension . '.category.' . $option->value) != true) + && (isset($oldParent)) + && $option->value != $oldParent + ) + { + { + unset($options[$i]); + } + } + } + } + if (($this->element['parent'] == true || $jinput->get('option') == 'com_categories') + && (isset($row) && !isset($options[0])) + && isset($this->element['show_root']) + ) + { + if ($row->parent_id == '1') + { + $parent = new stdClass; + $parent->text = JText::_('JGLOBAL_ROOT_PARENT'); + array_unshift($options, $parent); + } + array_unshift($options, JHtml::_('select.option', '0', JText::_('JGLOBAL_ROOT'))); + } + + // Merge any additional options in the XML definition. + $options = array_merge(parent::getOptions(), $options); + + return $options; + } +} diff --git a/administrator/components/com_categories/models/fields/categoryparent.php b/administrator/components/com_categories/models/fields/categoryparent.php new file mode 100644 index 0000000..c0290a3 --- /dev/null +++ b/administrator/components/com_categories/models/fields/categoryparent.php @@ -0,0 +1,174 @@ +element['name']; + + // Let's get the id for the current item, either category or content item. + $jinput = JFactory::getApplication()->input; + // For categories the old category is the category id 0 for new category. + if ($this->element['parent']) + { + $oldCat = $jinput->get('id', 0); + } + else + // For items the old category is the category they are in when opened or 0 if new. + { + $oldCat = $this->form->getValue($name); + } + + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('a.id AS value, a.title AS text, a.level') + ->from('#__categories AS a') + ->join('LEFT', $db->quoteName('#__categories') . ' AS b ON a.lft > b.lft AND a.rgt < b.rgt'); + + // Filter by the type + if ($extension = $this->form->getValue('extension')) + { + $query->where('(a.extension = ' . $db->quote($extension) . ' OR a.parent_id = 0)'); + } + if ($this->element['parent']) + { + // Prevent parenting to children of this item. + if ($id = $this->form->getValue('id')) + { + $query->join('LEFT', $db->quoteName('#__categories') . ' AS p ON p.id = ' . (int) $id) + ->where('NOT(a.lft >= p.lft AND a.rgt <= p.rgt)'); + + $rowQuery = $db->getQuery(true); + $rowQuery->select('a.id AS value, a.title AS text, a.level, a.parent_id') + ->from('#__categories AS a') + ->where('a.id = ' . (int) $id); + $db->setQuery($rowQuery); + $row = $db->loadObject(); + } + } + $query->where('a.published IN (0,1)') + ->group('a.id, a.title, a.level, a.lft, a.rgt, a.extension, a.parent_id') + ->order('a.lft ASC'); + + // Get the options. + $db->setQuery($query); + + try + { + $options = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + } + + // Pad the option text with spaces using depth level as a multiplier. + for ($i = 0, $n = count($options); $i < $n; $i++) + { + // Translate ROOT + if ($options[$i]->level == 0) + { + $options[$i]->text = JText::_('JGLOBAL_ROOT_PARENT'); + } + + $options[$i]->text = str_repeat('- ', $options[$i]->level) . $options[$i]->text; + } + + // Get the current user object. + $user = JFactory::getUser(); + + // For new items we want a list of categories you are allowed to create in. + if ($oldCat == 0) + { + foreach ($options as $i => $option) + { + // To take save or create in a category you need to have create rights for that category + // unless the item is already in that category. + // Unset the option if the user isn't authorised for it. In this field assets are always categories. + if ($user->authorise('core.create', $extension . '.category.' . $option->value) != true) + { + unset($options[$i]); + } + } + } + // If you have an existing category id things are more complex. + else + { + //$categoryOld = $this->form->getValue($name); + foreach ($options as $i => $option) + { + // If you are only allowed to edit in this category but not edit.state, you should not get any + // option to change the category parent for a category or the category for a content item, + // but you should be able to save in that category. + if ($user->authorise('core.edit.state', $extension . '.category.' . $oldCat) != true) + { + if ($option->value != $oldCat) + { + echo 'y'; + unset($options[$i]); + } + } + // However, if you can edit.state you can also move this to another category for which you have + // create permission and you should also still be able to save in the current category. + elseif + (($user->authorise('core.create', $extension . '.category.' . $option->value) != true) + && $option->value != $oldCat + ) + { + echo 'x'; + unset($options[$i]); + } + } + } + + if (isset($row) && !isset($options[0])) + { + if ($row->parent_id == '1') + { + $parent = new stdClass; + $parent->text = JText::_('JGLOBAL_ROOT_PARENT'); + array_unshift($options, $parent); + } + } + + // Merge any additional options in the XML definition. + $options = array_merge(parent::getOptions(), $options); + + return $options; + } +} diff --git a/administrator/components/com_categories/models/fields/index.html b/administrator/components/com_categories/models/fields/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_categories/models/fields/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_categories/models/fields/modal/category.php b/administrator/components/com_categories/models/fields/modal/category.php new file mode 100644 index 0000000..1a3b412 --- /dev/null +++ b/administrator/components/com_categories/models/fields/modal/category.php @@ -0,0 +1,161 @@ +element['extension'] ? (string) $this->element['extension'] : (string) JFactory::getApplication()->input->get('extension', 'com_content'); + + $allowEdit = ((string) $this->element['edit'] == 'true') ? true : false; + $allowClear = ((string) $this->element['clear'] != 'false') ? true : false; + + // Load language + JFactory::getLanguage()->load('com_categories', JPATH_ADMINISTRATOR); + + // Load the modal behavior script. + JHtml::_('behavior.modal', 'a.modal'); + + // Build the script. + $script = array(); + + // Select button script + $script[] = ' function jSelectCategory_'.$this->id.'(id, title, object) {'; + $script[] = ' document.getElementById("'.$this->id.'_id").value = id;'; + $script[] = ' document.getElementById("'.$this->id.'_name").value = title;'; + + if ($allowEdit) + { + $script[] = ' jQuery("#'.$this->id.'_edit").removeClass("hidden");'; + } + + if ($allowClear) + { + $script[] = ' jQuery("#'.$this->id.'_clear").removeClass("hidden");'; + } + + $script[] = ' SqueezeBox.close();'; + $script[] = ' }'; + + // Clear button script + static $scriptClear; + + if ($allowClear && !$scriptClear) + { + $scriptClear = true; + + $script[] = ' function jClearCategory(id) {'; + $script[] = ' document.getElementById(id + "_id").value = "";'; + $script[] = ' document.getElementById(id + "_name").value = "'.htmlspecialchars(JText::_('COM_CATEGORIES_SELECT_A_CATEGORY', true), ENT_COMPAT, 'UTF-8').'";'; + $script[] = ' jQuery("#"+id + "_clear").addClass("hidden");'; + $script[] = ' if (document.getElementById(id + "_edit")) {'; + $script[] = ' jQuery("#"+id + "_edit").addClass("hidden");'; + $script[] = ' }'; + $script[] = ' return false;'; + $script[] = ' }'; + } + + // Add the script to the document head. + JFactory::getDocument()->addScriptDeclaration(implode("\n", $script)); + + // Setup variables for display. + $html = array(); + $link = 'index.php?option=com_categories&view=categories&layout=modal&tmpl=component&extension='.$extension.'&function=jSelectCategory_'.$this->id; + + if (isset($this->element['language'])) + { + $link .= '&forcedLanguage='.$this->element['language']; + } + + $db = JFactory::getDbo(); + $db->setQuery( + 'SELECT title' . + ' FROM #__categories' . + ' WHERE id = '.(int) $this->value + ); + + try + { + $title = $db->loadResult(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + } + + if (empty($title)) + { + $title = JText::_('COM_CATEGORIES_SELECT_A_CATEGORY'); + } + $title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); + + // The active category id field. + if (0 == (int) $this->value) + { + $value = ''; + } + else + { + $value = (int) $this->value; + } + + // The current category display field. + $html[] = ''; + $html[] = ''; + $html[] = ' '.JText::_('JSELECT').''; + + // Edit category button + if ($allowEdit) + { + $html[] = ' ' . JText::_('JACTION_EDIT') . ''; + } + + // Clear category button + if ($allowClear) + { + $html[] = ''; + } + + $html[] = ''; + + // class='required' for client side validation + $class = ''; + if ($this->required) + { + $class = ' class="required modal-value"'; + } + + $html[] = ''; + + return implode("\n", $html); + } +} diff --git a/administrator/components/com_categories/models/fields/modal/index.html b/administrator/components/com_categories/models/fields/modal/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_categories/models/fields/modal/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_categories/models/forms/category.xml b/administrator/components/com_categories/models/forms/category.xml new file mode 100644 index 0000000..b193bd4 --- /dev/null +++ b/administrator/components/com_categories/models/forms/category.xml @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+
+ + +
+ + + + + + + + + +
+
+ diff --git a/administrator/components/com_categories/models/forms/index.html b/administrator/components/com_categories/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_categories/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_categories/models/index.html b/administrator/components/com_categories/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_categories/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_categories/tables/category.php b/administrator/components/com_categories/tables/category.php new file mode 100644 index 0000000..a42715c --- /dev/null +++ b/administrator/components/com_categories/tables/category.php @@ -0,0 +1,36 @@ + diff --git a/administrator/components/com_categories/views/categories/index.html b/administrator/components/com_categories/views/categories/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_categories/views/categories/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_categories/views/categories/tmpl/default.php b/administrator/components/com_categories/views/categories/tmpl/default.php new file mode 100644 index 0000000..1784222 --- /dev/null +++ b/administrator/components/com_categories/views/categories/tmpl/default.php @@ -0,0 +1,244 @@ +get('id'); +$extension = $this->escape($this->state->get('filter.extension')); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$ordering = ($listOrder == 'a.lft'); +$saveOrder = ($listOrder == 'a.lft' && $listDirn == 'asc'); +if ($saveOrder) +{ + $saveOrderingUrl = 'index.php?option=com_categories&task=categories.saveOrderAjax&tmpl=component'; + JHtml::_('sortablelist.sortable', 'categoryList', 'adminForm', strtolower($listDirn), $saveOrderingUrl, false, true); +} +$sortFields = $this->getSortFields(); +?> + +
+ sidebar)) : ?> +
+ sidebar; ?> +
+ +
sidebar) ? ' class="span10"' : ''; ?>> +
+ +
+ + +
+
+ + pagination->getLimitBox(); ?> +
+
+ + +
+
+ + +
+
+
+ + + + + + + + + + assoc) : ?> + + + + + + + + + + + + + + items as $i => $item) : ?> + id, $this->ordering[$item->parent_id]); + $canEdit = $user->authorise('core.edit', $extension . '.category.' . $item->id); + $canCheckin = $user->authorise('core.admin', 'com_checkin') || $item->checked_out == $userId || $item->checked_out == 0; + $canEditOwn = $user->authorise('core.edit.own', $extension . '.category.' . $item->id) && $item->created_user_id == $userId; + $canChange = $user->authorise('core.edit.state', $extension . '.category.' . $item->id) && $canCheckin; + + // Get the parents of item for sorting + if ($item->level > 1) + { + $parentsStr = ""; + $_currentParentId = $item->parent_id; + $parentsStr = " " . $_currentParentId; + for ($i2 = 0; $i2 < $item->level; $i2++) + { + foreach ($this->ordering as $k => $v) + { + $v = implode("-", $v); + $v = "-" . $v . "-"; + if (strpos($v, "-" . $_currentParentId . "-") !== false) + { + $parentsStr .= " " . $k; + $_currentParentId = $k; + break; + } + } + } + } + else + { + $parentsStr = ""; + } + ?> + + + + + + + assoc) : ?> + + + + + + + +
+ ', 'a.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING'); ?> + + + + + + + + + + + + state->get('list.direction'), $this->state->get('list.ordering')); ?> + + +
+ pagination->getListFooter(); ?> +
+ + + + + + + + + id); ?> + + published, $i, 'categories.', $canChange); ?> + + —', $item->level - 1) ?> + checked_out) : ?> + editor, $item->checked_out_time, 'categories.', $canCheckin); ?> + + + + escape($item->title); ?> + + escape($item->title); ?> + + + note)) : ?> + escape($item->alias)); ?> + + escape($item->alias), $this->escape($item->note)); ?> + + + + escape($item->access_level); ?> + + association): ?> + id, $extension); ?> + + + language == '*') : ?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + + id; ?> +
+ + loadTemplate('batch'); ?> + + + + + + + + +
+
diff --git a/administrator/components/com_categories/views/categories/tmpl/default_batch.php b/administrator/components/com_categories/views/categories/tmpl/default_batch.php new file mode 100644 index 0000000..3e437a3 --- /dev/null +++ b/administrator/components/com_categories/views/categories/tmpl/default_batch.php @@ -0,0 +1,70 @@ +state->get('filter.published'); +$extension = $this->escape($this->state->get('filter.extension')); +?> + diff --git a/administrator/components/com_categories/views/categories/tmpl/index.html b/administrator/components/com_categories/views/categories/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_categories/views/categories/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_categories/views/categories/tmpl/modal.php b/administrator/components/com_categories/views/categories/tmpl/modal.php new file mode 100644 index 0000000..5bd8be8 --- /dev/null +++ b/administrator/components/com_categories/views/categories/tmpl/modal.php @@ -0,0 +1,152 @@ +isSite()) +{ + JSession::checkToken('get') or die(JText::_('JINVALID_TOKEN')); +} + +require_once JPATH_ROOT . '/components/com_content/helpers/route.php'; + +// Include the component HTML helpers. +JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html'); +JHtml::_('bootstrap.tooltip'); + +$extension = $this->escape($this->state->get('filter.extension')); +$function = $app->input->getCmd('function', 'jSelectCategory'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +?> + +
+
+
+
+ +
+
+ +
+
+ + +
+
+
+
+
+ + + + + state->get('filter.forcedLanguage')) : ?> + + + + + +
+
+ + + + + + + + + + + + + + + + + items as $i => $item) : ?> + language && JLanguageMultilang::isEnabled()) + { + $tag = strlen($item->language); + if ($tag == 5) + { + $lang = substr($item->language, 0, 2); + } + elseif ($tag == 6) + { + $lang = substr($item->language, 0, 3); + } + else { + $lang = ""; + } + } + elseif (!JLanguageMultilang::isEnabled()) + { + $lang = ""; + } + ?> + + + + + + + + +
+ + + + + state->get('list.direction'), $this->state->get('list.ordering')); ?> + + +
+ pagination->getListFooter(); ?> +
+ —', $item->level - 1) ?> + + escape($item->title); ?> + + + escape($item->access_level); ?> + + language == '*'):?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + id; ?> +
+ + + + + + + + +
diff --git a/administrator/components/com_categories/views/categories/view.html.php b/administrator/components/com_categories/views/categories/view.html.php new file mode 100644 index 0000000..7a6d1a9 --- /dev/null +++ b/administrator/components/com_categories/views/categories/view.html.php @@ -0,0 +1,257 @@ +state = $this->get('State'); + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->assoc = $this->get('Assoc'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + // Preprocess the list of items to find ordering divisions. + foreach ($this->items as &$item) + { + $this->ordering[$item->parent_id][] = $item->id; + } + + // Levels filter. + $options = array(); + $options[] = JHtml::_('select.option', '1', JText::_('J1')); + $options[] = JHtml::_('select.option', '2', JText::_('J2')); + $options[] = JHtml::_('select.option', '3', JText::_('J3')); + $options[] = JHtml::_('select.option', '4', JText::_('J4')); + $options[] = JHtml::_('select.option', '5', JText::_('J5')); + $options[] = JHtml::_('select.option', '6', JText::_('J6')); + $options[] = JHtml::_('select.option', '7', JText::_('J7')); + $options[] = JHtml::_('select.option', '8', JText::_('J8')); + $options[] = JHtml::_('select.option', '9', JText::_('J9')); + $options[] = JHtml::_('select.option', '10', JText::_('J10')); + + $this->f_levels = $options; + + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + $categoryId = $this->state->get('filter.category_id'); + $component = $this->state->get('filter.component'); + $section = $this->state->get('filter.section'); + $canDo = null; + $user = JFactory::getUser(); + $extension = JFactory::getApplication()->input->get('extension', '', 'word'); + + // Get the toolbar object instance + $bar = JToolBar::getInstance('toolbar'); + + // Avoid nonsense situation. + if ($component == 'com_categories') + { + return; + } + + // Need to load the menu language file as mod_menu hasn't been loaded yet. + $lang = JFactory::getLanguage(); + $lang->load($component, JPATH_BASE, null, false, false) + || $lang->load($component, JPATH_ADMINISTRATOR . '/components/' . $component, null, false, false) + || $lang->load($component, JPATH_BASE, $lang->getDefault(), false, false) + || $lang->load($component, JPATH_ADMINISTRATOR . '/components/' . $component, $lang->getDefault(), false, false); + + // Load the category helper. + require_once JPATH_COMPONENT . '/helpers/categories.php'; + + // Get the results for each action. + $canDo = CategoriesHelper::getActions($component, $categoryId); + + // If a component categories title string is present, let's use it. + if ($lang->hasKey($component_title_key = strtoupper($component . ($section ? "_$section" : '')) . '_CATEGORIES_TITLE')) + { + $title = JText::_($component_title_key); + } + // Else if the component section string exits, let's use it + elseif ($lang->hasKey($component_section_key = strtoupper($component . ($section ? "_$section" : '')))) + { + $title = JText::sprintf('COM_CATEGORIES_CATEGORIES_TITLE', $this->escape(JText::_($component_section_key))); + } + // Else use the base title + else + { + $title = JText::_('COM_CATEGORIES_CATEGORIES_BASE_TITLE'); + } + + // Load specific css component + JHtml::_('stylesheet', $component . '/administrator/categories.css', array(), true); + + // Prepare the toolbar. + JToolbarHelper::title($title, 'categories ' . substr($component, 4) . ($section ? "-$section" : '') . '-categories'); + + if ($canDo->get('core.create') || (count($user->getAuthorisedCategories($component, 'core.create'))) > 0) + { + JToolbarHelper::addNew('category.add'); + } + + if ($canDo->get('core.edit') || $canDo->get('core.edit.own')) + { + JToolbarHelper::editList('category.edit'); + } + + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::publish('categories.publish', 'JTOOLBAR_PUBLISH', true); + JToolbarHelper::unpublish('categories.unpublish', 'JTOOLBAR_UNPUBLISH', true); + JToolbarHelper::archiveList('categories.archive'); + } + + if (JFactory::getUser()->authorise('core.admin')) + { + JToolbarHelper::checkin('categories.checkin'); + } + + if ($this->state->get('filter.published') == -2 && $canDo->get('core.delete', $component)) + { + JToolbarHelper::deleteList('', 'categories.delete', 'JTOOLBAR_EMPTY_TRASH'); + } + elseif ($canDo->get('core.edit.state')) + { + JToolbarHelper::trash('categories.trash'); + } + + // Add a batch button + if ($user->authorise('core.create', $extension) & $user->authorise('core.edit', $extension) && $user->authorise('core.edit.state', $extension)) + { + JHtml::_('bootstrap.modal', 'collapseModal'); + $title = JText::_('JTOOLBAR_BATCH'); + + // Instantiate a new JLayoutFile instance and render the batch button + $layout = new JLayoutFile('joomla.toolbar.batch'); + + $dhtml = $layout->render(array('title' => $title)); + $bar->appendButton('Custom', $dhtml, 'batch'); + } + + if ($canDo->get('core.admin')) + { + JToolbarHelper::custom('categories.rebuild', 'refresh.png', 'refresh_f2.png', 'JTOOLBAR_REBUILD', false); + JToolbarHelper::preferences($component); + } + + // Compute the ref_key if it does exist in the component + if (!$lang->hasKey($ref_key = strtoupper($component . ($section ? "_$section" : '')) . '_CATEGORIES_HELP_KEY')) + { + $ref_key = 'JHELP_COMPONENTS_' . strtoupper(substr($component, 4) . ($section ? "_$section" : '')) . '_CATEGORIES'; + } + + // Get help for the categories view for the component by + // -remotely searching in a language defined dedicated URL: *component*_HELP_URL + // -locally searching in a component help file if helpURL param exists in the component and is set to '' + // -remotely searching in a component URL if helpURL param exists in the component and is NOT set to '' + if ($lang->hasKey($lang_help_url = strtoupper($component) . '_HELP_URL')) + { + $debug = $lang->setDebug(false); + $url = JText::_($lang_help_url); + $lang->setDebug($debug); + } + else + { + $url = null; + } + JToolbarHelper::help($ref_key, JComponentHelper::getParams($component)->exists('helpURL'), $url); + + JHtmlSidebar::setAction('index.php?option=com_categories&view=categories'); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_MAX_LEVELS'), + 'filter_level', + JHtml::_('select.options', $this->f_levels, 'value', 'text', $this->state->get('filter.level')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_published', + JHtml::_('select.options', JHtml::_('jgrid.publishedOptions'), 'value', 'text', $this->state->get('filter.published'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_ACCESS'), + 'filter_access', + JHtml::_('select.options', JHtml::_('access.assetgroups'), 'value', 'text', $this->state->get('filter.access')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_LANGUAGE'), + 'filter_language', + JHtml::_('select.options', JHtml::_('contentlanguage.existing', true, true), 'value', 'text', $this->state->get('filter.language')) + ); + + if (JHelperTags::getTypes('objectList', array($extension . '.category'), true)) + { + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_TAG'), + 'filter_tag', + JHtml::_('select.options', JHtml::_('tag.options', true, true), 'value', 'text', $this->state->get('filter.tag')) + ); + } + + } + + /** + * Returns an array of fields the table can be sorted by + * + * @return array Array containing the field name to sort by as the key and display text as value + * + * @since 3.0 + */ + protected function getSortFields() + { + return array( + 'a.lft' => JText::_('JGRID_HEADING_ORDERING'), + 'a.published' => JText::_('JSTATUS'), + 'a.title' => JText::_('JGLOBAL_TITLE'), + 'a.access' => JText::_('JGRID_HEADING_ACCESS'), + 'language' => JText::_('JGRID_HEADING_LANGUAGE'), + 'a.id' => JText::_('JGRID_HEADING_ID') + ); + } +} diff --git a/administrator/components/com_categories/views/category/index.html b/administrator/components/com_categories/views/category/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_categories/views/category/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_categories/views/category/tmpl/edit.php b/administrator/components/com_categories/views/category/tmpl/edit.php new file mode 100644 index 0000000..94cebd3 --- /dev/null +++ b/administrator/components/com_categories/views/category/tmpl/edit.php @@ -0,0 +1,215 @@ +input; + +JHtml::_('behavior.formvalidation'); +JHtml::_('behavior.keepalive'); +JHtml::_('formbehavior.chosen', 'select'); + +?> + + + +
+ + + +
+ +
+ 'general')); ?> + + +
+
+ form->getLabel('title'); ?> +
+
+ form->getInput('title'); ?> +
+
+
+
+ form->getLabel('alias'); ?> +
+
+ form->getInput('alias'); ?> +
+
+
+
+ form->getLabel('description'); ?> +
+
+ form->getInput('description'); ?> +
+
+
+
+ form->getLabel('extension'); ?> +
+
+ form->getInput('extension'); ?> +
+
+ + + +
+
+ form->getLabel('id'); ?> +
+
+ form->getInput('id'); ?> +
+
+
+
+ form->getLabel('hits'); ?> +
+
+ form->getInput('hits'); ?> +
+
+
+
+ form->getLabel('created_user_id'); ?> +
+
+ form->getInput('created_user_id'); ?> +
+
+ item->created_time)) : ?> +
+
+ form->getLabel('created_time'); ?> +
+
+ form->getInput('created_time'); ?> +
+
+ + item->modified_user_id) : ?> +
+
+ form->getLabel('modified_user_id'); ?> +
+
+ form->getInput('modified_user_id'); ?> +
+
+
+
+ form->getLabel('modified_time'); ?> +
+
+ form->getInput('modified_time'); ?> +
+
+ + + + +
+ loadTemplate('options'); ?> +
+ + + +
+ loadTemplate('metadata'); ?> +
+ + + loadTemplate('extrafields'); ?> + + assoc) : ?> + +
+ loadTemplate('associations'); ?> +
+ + + + canDo->get('core.admin')) : ?> + +
+ form->getInput('rules'); ?> +
+ + + + + + + +
+ + +
+

+
+
+
+
+ form->getValue('title'); ?> +
+
+
+ form->getLabel('parent_id'); ?> +
+ form->getInput('parent_id'); ?> +
+
+
+ form->getLabel('published'); ?> +
+ form->getInput('published'); ?> +
+
+
+ form->getLabel('access'); ?> +
+ form->getInput('access'); ?> +
+
+
+ form->getLabel('language'); ?> +
+ form->getInput('language'); ?> +
+
+ checkTags) : ?> +
+ form->getLabel('tags'); ?> +
+ form->getInput('tags'); ?> +
+
+ +
+
+ +
+
diff --git a/administrator/components/com_categories/views/category/tmpl/edit_associations.php b/administrator/components/com_categories/views/category/tmpl/edit_associations.php new file mode 100644 index 0000000..64c9c45 --- /dev/null +++ b/administrator/components/com_categories/views/category/tmpl/edit_associations.php @@ -0,0 +1,12 @@ + + +form->getFieldsets('attribs'); ?> + $fieldSet) : ?> + label) ? $fieldSet->label : 'COM_CATEGORIES_' . $name . '_FIELDSET_LABEL'; ?> + + +
+ description) && trim($fieldSet->description)) : ?> +

escape(JText::_($fieldSet->description)); ?>

+ + form->getFieldset($name) as $field) : ?> +
+
+ label; ?> +
+
+ input; ?> +
+
+ +
+ + + + diff --git a/administrator/components/com_categories/views/category/tmpl/edit_metadata.php b/administrator/components/com_categories/views/category/tmpl/edit_metadata.php new file mode 100644 index 0000000..9162e21 --- /dev/null +++ b/administrator/components/com_categories/views/category/tmpl/edit_metadata.php @@ -0,0 +1,12 @@ + 'collapse0')); +$fieldSets = $this->form->getFieldsets('params'); +$i = 0; +?> + $fieldSet) : ?> + label) ? $fieldSet->label : 'COM_CATEGORIES_' . $name . '_FIELDSET_LABEL'; + echo JHtml::_('bootstrap.addSlide', 'categoryOptions', JText::_($label), 'collapse' . $i++); + if (isset($fieldSet->description) && trim($fieldSet->description)) + { + echo '

' . $this->escape(JText::_($fieldSet->description)) . '

'; + } + ?> + form->getFieldset($name) as $field) : ?> +
+
+ label; ?> +
+
+ input; ?> +
+
+ + + +
+
+ form->getLabel('note'); ?> +
+
+ form->getInput('note'); ?> +
+
+ + + + diff --git a/administrator/components/com_categories/views/category/tmpl/modal.php b/administrator/components/com_categories/views/category/tmpl/modal.php new file mode 100644 index 0000000..0de7168 --- /dev/null +++ b/administrator/components/com_categories/views/category/tmpl/modal.php @@ -0,0 +1,228 @@ +input; + +// Load the tooltip behavior. +JHtml::_('behavior.tooltip'); +JHtml::_('behavior.formvalidation'); +JHtml::_('behavior.keepalive'); +JHtml::_('formbehavior.chosen', 'select'); + +?> + + +
+ +
+ + + +
+ +
+
+ +
+
+ +
+ 'general')); ?> + + +
+
+ form->getLabel('title'); ?> +
+
+ form->getInput('title'); ?> +
+
+
+
+ form->getLabel('alias'); ?> +
+
+ form->getInput('alias'); ?> +
+
+
+
+ form->getLabel('description'); ?> +
+
+ form->getInput('description'); ?> +
+
+ form->getLabel('extension'); ?> +
+
+ form->getInput('extension'); ?> +
+
+ + + +
+
+ form->getLabel('id'); ?> +
+
+ form->getInput('id'); ?> +
+
+
+
+ form->getLabel('hits'); ?> +
+
+ form->getInput('hits'); ?> +
+
+
+
+ form->getLabel('created_user_id'); ?> +
+
+ form->getInput('created_user_id'); ?> +
+
+ item->created_time)) : ?> +
+
+ form->getLabel('created_time'); ?> +
+
+ form->getInput('created_time'); ?> +
+
+ + item->modified_user_id) : ?> +
+
+ form->getLabel('modified_user_id'); ?> +
+
+ form->getInput('modified_user_id'); ?> +
+
+
+
+ form->getLabel('modified_time'); ?> +
+
+ form->getInput('modified_time'); ?> +
+
+ + + + +
+ loadTemplate('options'); ?> +
+ + + + loadTemplate('metadata'); ?> + + + loadTemplate('extrafields'); ?> + + canDo->get('core.admin')) : ?> + +
+ form->getInput('rules'); ?> +
+ + + + + + + + + + +
+ + +
+

+
+
+
+
+ form->getValue('title'); ?> +
+
+
+ form->getLabel('parent_id'); ?> +
+ form->getInput('parent_id'); ?> +
+
+
+ form->getLabel('published'); ?> +
+ form->getInput('published'); ?> +
+
+
+ form->getLabel('access'); ?> +
+ form->getInput('access'); ?> +
+
+
+ form->getLabel('language'); ?> +
+ form->getInput('language'); ?> +
+
+
+ checkTags) : ?> +
+ form->getLabel('tags'); ?> +
+ form->getInput('tags'); ?> +
+
+ +
+
+
+ +
+
+
\ No newline at end of file diff --git a/administrator/components/com_categories/views/category/tmpl/modal_associations.php b/administrator/components/com_categories/views/category/tmpl/modal_associations.php new file mode 100644 index 0000000..64c9c45 --- /dev/null +++ b/administrator/components/com_categories/views/category/tmpl/modal_associations.php @@ -0,0 +1,12 @@ + + +form->getFieldsets('attribs'); ?> + $fieldSet) : ?> + label) ? $fieldSet->label : 'COM_CATEGORIES_'.$name.'_FIELDSET_LABEL'; ?> + + +
+ description) && trim($fieldSet->description)) : ?> +

escape(JText::_($fieldSet->description));?>

+ form->getFieldset($name) as $field) : ?> +
+
+ label; ?> +
+
+ input; ?> +
+
+ +
+ + + + diff --git a/administrator/components/com_categories/views/category/tmpl/modal_metadata.php b/administrator/components/com_categories/views/category/tmpl/modal_metadata.php new file mode 100644 index 0000000..7a51b33 --- /dev/null +++ b/administrator/components/com_categories/views/category/tmpl/modal_metadata.php @@ -0,0 +1,13 @@ + diff --git a/administrator/components/com_categories/views/category/tmpl/modal_options.php b/administrator/components/com_categories/views/category/tmpl/modal_options.php new file mode 100644 index 0000000..5212358 --- /dev/null +++ b/administrator/components/com_categories/views/category/tmpl/modal_options.php @@ -0,0 +1,47 @@ + + 'collapse0')); + $fieldSets = $this->form->getFieldsets('params'); + $i = 0; + + foreach ($fieldSets as $name => $fieldSet) : + $label = !empty($fieldSet->label) ? $fieldSet->label : 'COM_CATEGORIES_'.$name.'_FIELDSET_LABEL'; + echo JHtml::_('bootstrap.addSlide', 'categoryOptions', JText::_($label), 'collapse' . $i++); + if (isset($fieldSet->description) && trim($fieldSet->description)) : + echo '

'.$this->escape(JText::_($fieldSet->description)).'

'; + endif; + ?> + form->getFieldset($name) as $field) : ?> +
+
+ label; ?> +
+
+ input; ?> +
+
+ + + +
+
+ form->getLabel('note'); ?> +
+
+ form->getInput('note'); ?> +
+
+ form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + $this->canDo = CategoriesHelper::getActions($this->state->get('category.component')); + $this->assoc = $this->get('Assoc'); + + $input = JFactory::getApplication()->input; + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + // Check for tag type + $this->checkTags = JHelperTags::getTypes('objectList', array($this->state->get('category.extension') . '.category'), true); + + $input->set('hidemainmenu', true); + + if ($this->getLayout() == 'modal') + { + $this->form->setFieldAttribute('language', 'readonly', 'true'); + $this->form->setFieldAttribute('parent_id', 'readonly', 'true'); + } + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + $input = JFactory::getApplication()->input; + $extension = $input->get('extension'); + $user = JFactory::getUser(); + $userId = $user->get('id'); + + $isNew = ($this->item->id == 0); + $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $userId); + + // Check to see if the type exists + $ucmType = new JUcmType; + $this->typeId = $ucmType->getTypeId($extension . '.category'); + + // Avoid nonsense situation. + if ($extension == 'com_categories') + { + return; + } + + // The extension can be in the form com_foo.section + $parts = explode('.', $extension); + $component = $parts[0]; + $section = (count($parts) > 1) ? $parts[1] : null; + + // Need to load the menu language file as mod_menu hasn't been loaded yet. + $lang = JFactory::getLanguage(); + $lang->load($component, JPATH_BASE, null, false, false) + || $lang->load($component, JPATH_ADMINISTRATOR . '/components/' . $component, null, false, false) + || $lang->load($component, JPATH_BASE, $lang->getDefault(), false, false) + || $lang->load($component, JPATH_ADMINISTRATOR . '/components/' . $component, $lang->getDefault(), false, false); + + // Load the category helper. + require_once JPATH_COMPONENT . '/helpers/categories.php'; + + // Get the results for each action. + $canDo = CategoriesHelper::getActions($component, $this->item->id); + + // If a component categories title string is present, let's use it. + if ($lang->hasKey($component_title_key = $component . ($section ? "_$section" : '') . '_CATEGORY_' . ($isNew ? 'ADD' : 'EDIT') . '_TITLE')) + { + $title = JText::_($component_title_key); + } + // Else if the component section string exits, let's use it + elseif ($lang->hasKey($component_section_key = $component . ($section ? "_$section" : ''))) + { + $title = JText::sprintf('COM_CATEGORIES_CATEGORY_' . ($isNew ? 'ADD' : 'EDIT') . '_TITLE', $this->escape(JText::_($component_section_key))); + } + // Else use the base title + else + { + $title = JText::_('COM_CATEGORIES_CATEGORY_BASE_' . ($isNew ? 'ADD' : 'EDIT') . '_TITLE'); + } + + // Load specific css component + JHtml::_('stylesheet', $component . '/administrator/categories.css', array(), true); + + // Prepare the toolbar. + JToolbarHelper::title($title, 'category-' . ($isNew ? 'add' : 'edit') . ' ' . substr($component, 4) . ($section ? "-$section" : '') . '-category-' . ($isNew ? 'add' : 'edit')); + + // For new records, check the create permission. + if ($isNew && (count($user->getAuthorisedCategories($component, 'core.create')) > 0)) + { + JToolbarHelper::apply('category.apply'); + JToolbarHelper::save('category.save'); + JToolbarHelper::save2new('category.save2new'); + } + + // If not checked out, can save the item. + elseif (!$checkedOut && ($canDo->get('core.edit') || ($canDo->get('core.edit.own') && $this->item->created_user_id == $userId))) + { + JToolbarHelper::apply('category.apply'); + JToolbarHelper::save('category.save'); + if ($canDo->get('core.create')) + { + JToolbarHelper::save2new('category.save2new'); + } + } + + // If an existing item, can save to a copy. + if (!$isNew && $canDo->get('core.create')) + { + JToolbarHelper::save2copy('category.save2copy'); + } + + if (empty($this->item->id)) + { + JToolbarHelper::cancel('category.cancel'); + } + else + { + JToolbarHelper::cancel('category.cancel', 'JTOOLBAR_CLOSE'); + } + + JToolbarHelper::divider(); + + // Compute the ref_key if it does exist in the component + if (!$lang->hasKey($ref_key = strtoupper($component . ($section ? "_$section" : '')) . '_CATEGORY_' . ($isNew ? 'ADD' : 'EDIT') . '_HELP_KEY')) + { + $ref_key = 'JHELP_COMPONENTS_' . strtoupper(substr($component, 4) . ($section ? "_$section" : '')) . '_CATEGORY_' . ($isNew ? 'ADD' : 'EDIT'); + } + + // Get help for the category/section view for the component by + // -remotely searching in a language defined dedicated URL: *component*_HELP_URL + // -locally searching in a component help file if helpURL param exists in the component and is set to '' + // -remotely searching in a component URL if helpURL param exists in the component and is NOT set to '' + if ($lang->hasKey($lang_help_url = strtoupper($component) . '_HELP_URL')) + { + $debug = $lang->setDebug(false); + $url = JText::_($lang_help_url); + $lang->setDebug($debug); + } + else + { + $url = null; + } + JToolbarHelper::help($ref_key, JComponentHelper::getParams($component)->exists('helpURL'), $url, $component); + } +} diff --git a/administrator/components/com_categories/views/index.html b/administrator/components/com_categories/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_categories/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_checkin/checkin.php b/administrator/components/com_checkin/checkin.php new file mode 100644 index 0000000..d43bd9a --- /dev/null +++ b/administrator/components/com_checkin/checkin.php @@ -0,0 +1,19 @@ +authorise('core.manage', 'com_checkin')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$controller = JControllerLegacy::getInstance('Checkin'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_checkin/checkin.xml b/administrator/components/com_checkin/checkin.xml new file mode 100644 index 0000000..8b6b4b8 --- /dev/null +++ b/administrator/components/com_checkin/checkin.xml @@ -0,0 +1,26 @@ + + + com_checkin + Joomla! Project + (C) 2005 - 2008 Open Source Matters. All rights reserved. + + http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL + admin@joomla.org + www.joomla.org + 3.0.0 + COM_CHECKIN_XML_DESCRIPTION + + + checkin.php + config.xml + controller.php + index.html + models + views + + + language/en-GB.com_checkin.ini + language/en-GB.com_checkin.sys.ini + + + diff --git a/administrator/components/com_checkin/config.xml b/administrator/components/com_checkin/config.xml new file mode 100644 index 0000000..2a2238f --- /dev/null +++ b/administrator/components/com_checkin/config.xml @@ -0,0 +1,27 @@ + + +
+ + + + + +
+
diff --git a/administrator/components/com_checkin/controller.php b/administrator/components/com_checkin/controller.php new file mode 100644 index 0000000..1d2366c --- /dev/null +++ b/administrator/components/com_checkin/controller.php @@ -0,0 +1,82 @@ +addSubmenu($this->input->getWord('option', 'com_checkin')); + + parent::display(); + + return $this; + } + + public function checkin() + { + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JInvalid_Token')); + + $ids = $this->input->get('cid', array(), 'array'); + + if (empty($ids)) + { + JError::raiseWarning(500, JText::_('JLIB_HTML_PLEASE_MAKE_A_SELECTION_FROM_THE_LIST')); + } + else + { + // Get the model. + $model = $this->getModel(); + + // Checked in the items. + $this->setMessage(JText::plural('COM_CHECKIN_N_ITEMS_CHECKED_IN', $model->checkin($ids))); + } + + $this->setRedirect('index.php?option=com_checkin'); + } + + /** + * Configure the Linkbar. + * + * @param string $vName The name of the active view. + * + * @return void + * + * @since 1.6 + */ + protected function addSubmenu($vName) + { + JHtmlSidebar::addEntry( + JText::_('JGLOBAL_SUBMENU_CHECKIN'), + 'index.php?option=com_checkin', + $vName == 'com_checkin' + ); + + JHtmlSidebar::addEntry( + JText::_('JGLOBAL_SUBMENU_CLEAR_CACHE'), + 'index.php?option=com_cache', + $vName == 'cache' + ); + JHtmlSidebar::addEntry( + JText::_('JGLOBAL_SUBMENU_PURGE_EXPIRED_CACHE'), + 'index.php?option=com_cache&view=purge', + $vName == 'purge' + ); + } +} diff --git a/administrator/components/com_checkin/index.html b/administrator/components/com_checkin/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_checkin/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_checkin/models/checkin.php b/administrator/components/com_checkin/models/checkin.php new file mode 100644 index 0000000..63d8e8d --- /dev/null +++ b/administrator/components/com_checkin/models/checkin.php @@ -0,0 +1,200 @@ +getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + // List state information. + parent::populateState('table', 'asc'); + } + + /** + * Checks in requested tables + * + * @param array $ids An array of table names. Optional. + * + * @return integer Checked in item count + * + * @since 1.6 + */ + public function checkin($ids = array()) + { + $app = JFactory::getApplication(); + $db = $this->_db; + $nullDate = $db->getNullDate(); + + if (!is_array($ids)) + { + return; + } + + // this int will hold the checked item count + $results = 0; + + foreach ($ids as $tn) + { + // make sure we get the right tables based on prefix + if (stripos($tn, $app->getCfg('dbprefix')) !== 0) + { + continue; + } + + $fields = $db->getTableColumns($tn); + + if (!(isset($fields['checked_out']) && isset($fields['checked_out_time']))) + { + continue; + } + + $query = $db->getQuery(true) + ->update($db->quoteName($tn)) + ->set('checked_out = 0') + ->set('checked_out_time = ' . $db->quote($nullDate)) + ->where('checked_out > 0'); + + $db->setQuery($query); + if ($db->execute()) + { + $results = $results + $db->getAffectedRows(); + } + } + return $results; + } + + /** + * Get total of tables + * + * @return int Total to check-in tables + * + * @since 1.6 + */ + public function getTotal() + { + if (!isset($this->total)) + { + $this->getItems(); + } + return $this->total; + } + + /** + * Get tables + * + * @return array Checked in table names as keys and checked in item count as values + * + * @since 1.6 + */ + public function getItems() + { + if (!isset($this->items)) + { + $app = JFactory::getApplication(); + $db = $this->_db; + $tables = $db->getTableList(); + + // this array will hold table name as key and checked in item count as value + $results = array(); + + foreach ($tables as $i => $tn) + { + // make sure we get the right tables based on prefix + if (stripos($tn, $app->getCfg('dbprefix')) !== 0) + { + unset($tables[$i]); + continue; + } + + if ($this->getState('filter.search') && stripos($tn, $this->getState('filter.search')) === false) + { + unset($tables[$i]); + continue; + } + + $fields = $db->getTableColumns($tn); + + if (!(isset($fields['checked_out']) && isset($fields['checked_out_time']))) + { + unset($tables[$i]); + continue; + } + } + foreach ($tables as $tn) + { + $query = $db->getQuery(true) + ->select('COUNT(*)') + ->from($db->quoteName($tn)) + ->where('checked_out > 0'); + + $db->setQuery($query); + if ($db->execute()) + { + $results[$tn] = $db->loadResult(); + } + else + { + continue; + } + } + $this->total = count($results); + if ($this->getState('list.ordering') == 'table') + { + if ($this->getState('list.direction') == 'asc') + { + ksort($results); + } + else + { + krsort($results); + } + } + else + { + if ($this->getState('list.direction') == 'asc') + { + asort($results); + } + else + { + arsort($results); + } + } + $results = array_slice($results, $this->getState('list.start'), $this->getState('list.limit') ? $this->getState('list.limit') : null); + $this->items = $results; + } + return $this->items; + } +} diff --git a/administrator/components/com_checkin/models/index.html b/administrator/components/com_checkin/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_checkin/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_checkin/views/checkin/index.html b/administrator/components/com_checkin/views/checkin/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_checkin/views/checkin/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_checkin/views/checkin/tmpl/default.php b/administrator/components/com_checkin/views/checkin/tmpl/default.php new file mode 100644 index 0000000..a2f9cb0 --- /dev/null +++ b/administrator/components/com_checkin/views/checkin/tmpl/default.php @@ -0,0 +1,69 @@ +escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +?> +
+ sidebar)) : ?> +
+ sidebar; ?> +
+ +
sidebar) ? ' class="span10"' : ''; ?>> +
+ +
+ + +
+
+
+ + + + + + + + + + items as $table => $count): $i = 0; ?> + + + + + + + + + + + + +
+ +
+ pagination->getListFooter(); ?> +
+ + + + + +
+
diff --git a/administrator/components/com_checkin/views/checkin/tmpl/index.html b/administrator/components/com_checkin/views/checkin/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_checkin/views/checkin/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_checkin/views/checkin/view.html.php b/administrator/components/com_checkin/views/checkin/view.html.php new file mode 100644 index 0000000..e287e8e --- /dev/null +++ b/administrator/components/com_checkin/views/checkin/view.html.php @@ -0,0 +1,58 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + JToolbarHelper::title(JText::_('COM_CHECKIN_GLOBAL_CHECK_IN'), 'checkin.png'); + if (JFactory::getUser()->authorise('core.admin', 'com_checkin')) + { + JToolbarHelper::custom('checkin', 'checkin.png', 'checkin_f2.png', 'JTOOLBAR_CHECKIN', true); + JToolbarHelper::divider(); + JToolbarHelper::preferences('com_checkin'); + JToolbarHelper::divider(); + } + JToolbarHelper::help('JHELP_SITE_MAINTENANCE_GLOBAL_CHECK-IN'); + } +} diff --git a/administrator/components/com_checkin/views/index.html b/administrator/components/com_checkin/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_checkin/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_config/config.php b/administrator/components/com_config/config.php new file mode 100644 index 0000000..dba688d --- /dev/null +++ b/administrator/components/com_config/config.php @@ -0,0 +1,19 @@ +execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_config/config.xml b/administrator/components/com_config/config.xml new file mode 100644 index 0000000..45af554 --- /dev/null +++ b/administrator/components/com_config/config.xml @@ -0,0 +1,26 @@ + + + com_config + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_CONFIG_XML_DESCRIPTION + + + config.php + controller.php + index.html + controllers + models + views + + + language/en-GB.com_config.ini + language/en-GB.com_config.sys.ini + + + diff --git a/administrator/components/com_config/controller.php b/administrator/components/com_config/controller.php new file mode 100644 index 0000000..dba68b1 --- /dev/null +++ b/administrator/components/com_config/controller.php @@ -0,0 +1,73 @@ +input->get('view', 'application'); + $vFormat = $document->getType(); + $lName = $this->input->get('layout', 'default'); + + // Get and render the view. + if ($view = $this->getView($vName, $vFormat)) + { + if ($vName != 'close') + { + // Get the model for the view. + $model = $this->getModel($vName); + + // Access check. + if (!JFactory::getUser()->authorise('core.admin', $model->getState('component.option'))) + { + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); + } + + // Push the model into the view (as default). + $view->setModel($model, true); + } + + $view->setLayout($lName); + + // Push document object into the view. + $view->document = $document; + + $view->display(); + } + } +} diff --git a/administrator/components/com_config/controllers/application.php b/administrator/components/com_config/controllers/application.php new file mode 100644 index 0000000..a63f461 --- /dev/null +++ b/administrator/components/com_config/controllers/application.php @@ -0,0 +1,215 @@ +registerTask('apply', 'save'); + } + + /** + * Method to save the configuration. + * + * @return bool True on success, false on failure. + * + * @since 1.5 + */ + public function save() + { + // Check for request forgeries. + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Check if the user is authorized to do this. + if (!JFactory::getUser()->authorise('core.admin')) + { + JFactory::getApplication()->redirect('index.php', JText::_('JERROR_ALERTNOAUTHOR')); + return; + } + + // Set FTP credentials, if given. + JClientHelper::setCredentialsFromRequest('ftp'); + + $app = JFactory::getApplication(); + $model = $this->getModel('Application'); + $form = $model->getForm(); + $data = $this->input->post->get('jform', array(), 'array'); + + // Validate the posted data. + $return = $model->validate($form, $data); + + // Check for validation errors. + if ($return === false) + { + // Get the validation messages. + $errors = $model->getErrors(); + + // Push up to three validation messages out to the user. + for ($i = 0, $n = count($errors); $i < $n && $i < 3; $i++) + { + if ($errors[$i] instanceof Exception) + { + $app->enqueueMessage($errors[$i]->getMessage(), 'warning'); + } + else + { + $app->enqueueMessage($errors[$i], 'warning'); + } + } + + // Save the data in the session. + $app->setUserState('com_config.config.global.data', $data); + + // Redirect back to the edit screen. + $this->setRedirect(JRoute::_('index.php?option=com_config&view=application', false)); + return false; + } + + // Attempt to save the configuration. + $data = $return; + $return = $model->save($data); + + // Check the return value. + if ($return === false) + { + // Save the data in the session. + $app->setUserState('com_config.config.global.data', $data); + + // Save failed, go back to the screen and display a notice. + $message = JText::sprintf('JERROR_SAVE_FAILED', $model->getError()); + $this->setRedirect('index.php?option=com_config&view=application', $message, 'error'); + return false; + } + + // Set the success message. + $message = JText::_('COM_CONFIG_SAVE_SUCCESS'); + + // Set the redirect based on the task. + switch ($this->getTask()) + { + case 'apply': + $this->setRedirect('index.php?option=com_config', $message); + break; + + case 'save': + default: + $this->setRedirect('index.php', $message); + break; + } + + return true; + } + + /** + * Cancel operation + */ + public function cancel() + { + // Check if the user is authorized to do this. + if (!JFactory::getUser()->authorise('core.admin', 'com_config')) + { + JFactory::getApplication()->redirect('index.php', JText::_('JERROR_ALERTNOAUTHOR')); + return; + } + + // Set FTP credentials, if given + JClientHelper::setCredentialsFromRequest('ftp'); + + // Clean the session data. + $app = JFactory::getApplication(); + $app->setUserState('com_config.config.global.data', null); + + $this->setRedirect('index.php'); + } + + public function refreshHelp() + { + jimport('joomla.filesystem.file'); + + // Set FTP credentials, if given + JClientHelper::setCredentialsFromRequest('ftp'); + + if (($data = file_get_contents('http://help.joomla.org/helpsites.xml')) === false) + { + $this->setRedirect('index.php?option=com_config', JText::_('COM_CONFIG_ERROR_HELPREFRESH_FETCH'), 'error'); + } + elseif (!JFile::write(JPATH_BASE . '/help/helpsites.xml', $data)) + { + $this->setRedirect('index.php?option=com_config', JText::_('COM_CONFIG_ERROR_HELPREFRESH_ERROR_STORE'), 'error'); + } + else + { + $this->setRedirect('index.php?option=com_config', JText::_('COM_CONFIG_HELPREFRESH_SUCCESS')); + } + } + + /** + * Method to remove the root property from the configuration. + * + * @return bool True on success, false on failure. + * + * @since 1.5 + */ + public function removeroot() + { + // Check for request forgeries. + JSession::checkToken('get') or die('Invalid Token'); + + // Check if the user is authorized to do this. + if (!JFactory::getUser()->authorise('core.admin')) + { + JFactory::getApplication()->redirect('index.php', JText::_('JERROR_ALERTNOAUTHOR')); + return; + } + + // Initialise model. + $model = $this->getModel('Application'); + + // Attempt to save the configuration and remove root. + $return = $model->removeroot(); + + // Check the return value. + if ($return === false) + { + // Save failed, go back to the screen and display a notice. + $this->setMessage(JText::sprintf('JERROR_SAVE_FAILED', $model->getError()), 'error'); + $this->setRedirect('index.php'); + return false; + } + + // Set the success message. + $message = JText::_('COM_CONFIG_SAVE_SUCCESS'); + + // Set the redirect based on the task. + $this->setRedirect('index.php', $message); + + return true; + } +} diff --git a/administrator/components/com_config/controllers/component.php b/administrator/components/com_config/controllers/component.php new file mode 100644 index 0000000..78a4f5c --- /dev/null +++ b/administrator/components/com_config/controllers/component.php @@ -0,0 +1,165 @@ +registerTask('apply', 'save'); + } + + /** + * Cancel operation + * + * @return void + * + * @since 3.0 + */ + function cancel() + { + // Clean the session data. + $app = JFactory::getApplication(); + $app->setUserState('com_config.config.global.data', null); + + $return = $this->input->post->get('return', null, 'base64'); + $redirect = 'index.php'; + if (!empty($return)) + { + $redirect = base64_decode($return); + } + + $this->setRedirect($redirect); + } + + /** + * Save the configuration + */ + public function save() + { + // Check for request forgeries. + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Set FTP credentials, if given. + JClientHelper::setCredentialsFromRequest('ftp'); + + $app = JFactory::getApplication(); + $model = $this->getModel('Component'); + $form = $model->getForm(); + $data = $this->input->get('jform', array(), 'array'); + $id = $this->input->getInt('id'); + $option = $this->input->get('component'); + + // Check if the user is authorized to do this. + if (!JFactory::getUser()->authorise('core.admin', $option)) + { + JFactory::getApplication()->redirect('index.php', JText::_('JERROR_ALERTNOAUTHOR')); + return; + } + + $returnUri = $this->input->post->get('return', null, 'base64'); + if (!empty($returnUri)) + { + $redirect = '&return=' . urlencode($returnUri); + } + + // Validate the posted data. + $return = $model->validate($form, $data); + + // Check for validation errors. + if ($return === false) + { + // Get the validation messages. + $errors = $model->getErrors(); + + // Push up to three validation messages out to the user. + for ($i = 0, $n = count($errors); $i < $n && $i < 3; $i++) + { + if ($errors[$i] instanceof Exception) + { + $app->enqueueMessage($errors[$i]->getMessage(), 'warning'); + } + else + { + $app->enqueueMessage($errors[$i], 'warning'); + } + } + + // Save the data in the session. + $app->setUserState('com_config.config.global.data', $data); + + // Redirect back to the edit screen. + $this->setRedirect(JRoute::_('index.php?option=com_config&view=component&component=' . $option . $redirect, false)); + return false; + } + + // Attempt to save the configuration. + $data = array( + 'params' => $return, + 'id' => $id, + 'option' => $option + ); + $return = $model->save($data); + + // Check the return value. + if ($return === false) + { + // Save the data in the session. + $app->setUserState('com_config.config.global.data', $data); + + // Save failed, go back to the screen and display a notice. + $message = JText::sprintf('JERROR_SAVE_FAILED', $model->getError()); + $this->setRedirect('index.php?option=com_config&view=component&component=' . $option . $redirect, $message, 'error'); + return false; + } + + // Set the redirect based on the task. + switch ($this->getTask()) + { + case 'apply': + $message = JText::_('COM_CONFIG_SAVE_SUCCESS'); + + $this->setRedirect('index.php?option=com_config&view=component&component=' . $option . $redirect, $message); + break; + + case 'save': + default: + $redirect = 'index.php'; + if (!empty($returnUri)) + { + $redirect = base64_decode($returnUri); + } + + $this->setRedirect($redirect); + break; + } + + return true; + } +} diff --git a/administrator/components/com_config/controllers/index.html b/administrator/components/com_config/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_config/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_config/helper/component.php b/administrator/components/com_config/helper/component.php new file mode 100644 index 0000000..6484c45 --- /dev/null +++ b/administrator/components/com_config/helper/component.php @@ -0,0 +1,112 @@ +getQuery(true) + ->select('element') + ->from('#__extensions') + ->where('type = ' . $db->quote('component')) + ->where('enabled = 1'); + $db->setQuery($query); + $result = $db->loadColumn(); + + return $result; + } + + /** + * Returns true if the component has configuration options. + * + * @param string $components + * + * @return boolean + * + * @since 3.0 + */ + public static function hasComponentConfig($component) + { + return is_file(JPATH_ADMINISTRATOR . '/components/' . $component . '/config.xml'); + } + + /** + * Returns an array of all components with configuration options. By only + * components for which the current user has 'core.manage' rights are returned. + * + * @param boolean $authCheck + * + * @return array + * + * @since 3.0 + */ + public static function getComponentsWithConfig($authCheck = true) + { + $result = array(); + $components = self::getAllComponents(); + $user = JFactory::getUser(); + + // Remove com_config from the array as that may have weird side effects + $components = array_diff($components, array('com_config')); + + foreach ($components as $component) + { + if (self::hasComponentConfig($component) && (!$authCheck || $user->authorise('core.manage', $component))) + { + $result[] = $component; + } + } + + return $result; + } + + /** + * Load the sys language for the given component. + * + * @param string $components + * + * @return void + * + * @since 3.0 + */ + public static function loadLanguageForComponents($components) + { + $lang = JFactory::getLanguage(); + + foreach ($components as $component) + { + if (!empty($component)) + { + // Load the core file then + // Load extension-local file. + $lang->load($component . '.sys', JPATH_BASE, null, false, false) + || $lang->load($component . '.sys', JPATH_ADMINISTRATOR . '/components/' . $component, null, false, false) + || $lang->load($component . '.sys', JPATH_BASE, $lang->getDefault(), false, false) + || $lang->load($component . '.sys', JPATH_ADMINISTRATOR . '/components/' . $component, $lang->getDefault(), false, false); + } + } + } +} diff --git a/administrator/components/com_config/helper/index.html b/administrator/components/com_config/helper/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_config/helper/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_config/index.html b/administrator/components/com_config/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_config/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_config/models/application.php b/administrator/components/com_config/models/application.php new file mode 100644 index 0000000..a43440a --- /dev/null +++ b/administrator/components/com_config/models/application.php @@ -0,0 +1,279 @@ +loadForm('com_config.application', 'application', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + return $form; + } + + /** + * Method to get the configuration data. + * + * This method will load the global configuration data straight from + * JConfig. If configuration data has been saved in the session, that + * data will be merged into the original data, overwriting it. + * + * @return array An array containg all global config data. + * + * @since 1.6 + */ + public function getData() + { + // Get the config data. + $config = new JConfig; + $data = JArrayHelper::fromObject($config); + + // Prime the asset_id for the rules. + $data['asset_id'] = 1; + + // Get the text filter data + $params = JComponentHelper::getParams('com_config'); + $data['filters'] = JArrayHelper::fromObject($params->get('filters')); + + // If no filter data found, get from com_content (update of 1.6/1.7 site) + if (empty($data['filters'])) + { + $contentParams = JComponentHelper::getParams('com_content'); + $data['filters'] = JArrayHelper::fromObject($contentParams->get('filters')); + } + + // Check for data in the session. + $temp = JFactory::getApplication()->getUserState('com_config.config.global.data'); + + // Merge in the session data. + if (!empty($temp)) + { + $data = array_merge($data, $temp); + } + + $this->preprocessData('com_config.application', $data); + + return $data; + } + + /** + * Method to save the configuration data. + * + * @param array $data An array containing all global config data. + * + * @return bool True on success, false on failure. + * + * @since 1.6 + */ + public function save($data) + { + // Save the rules + if (isset($data['rules'])) + { + $rules = new JAccessRules($data['rules']); + + // Check that we aren't removing our Super User permission + // Need to get groups from database, since they might have changed + $myGroups = JAccess::getGroupsByUser(JFactory::getUser()->get('id')); + $myRules = $rules->getData(); + $hasSuperAdmin = $myRules['core.admin']->allow($myGroups); + if (!$hasSuperAdmin) + { + $this->setError(JText::_('COM_CONFIG_ERROR_REMOVING_SUPER_ADMIN')); + return false; + } + + $asset = JTable::getInstance('asset'); + if ($asset->loadByName('root.1')) + { + $asset->rules = (string) $rules; + + if (!$asset->check() || !$asset->store()) + { + JError::raiseNotice('SOME_ERROR_CODE', $asset->getError()); + } + } + else + { + $this->setError(JText::_('COM_CONFIG_ERROR_ROOT_ASSET_NOT_FOUND')); + return false; + } + unset($data['rules']); + } + + // Save the text filters + if (isset($data['filters'])) + { + $registry = new JRegistry; + $registry->loadArray(array('filters' => $data['filters'])); + + $extension = JTable::getInstance('extension'); + + // Get extension_id + $extension_id = $extension->find(array('name' => 'com_config')); + + if ($extension->load((int) $extension_id)) + { + $extension->params = (string) $registry; + if (!$extension->check() || !$extension->store()) + { + JError::raiseNotice('SOME_ERROR_CODE', $extension->getError()); + } + } + else + { + $this->setError(JText::_('COM_CONFIG_ERROR_CONFIG_EXTENSION_NOT_FOUND')); + return false; + } + unset($data['filters']); + } + + // Get the previous configuration. + $prev = new JConfig; + $prev = JArrayHelper::fromObject($prev); + + // Merge the new data in. We do this to preserve values that were not in the form. + $data = array_merge($prev, $data); + + /* + * Perform miscellaneous options based on configuration settings/changes. + */ + // Escape the offline message if present. + if (isset($data['offline_message'])) + { + $data['offline_message'] = JFilterOutput::ampReplace($data['offline_message']); + } + + // Purge the database session table if we are changing to the database handler. + if ($prev['session_handler'] != 'database' && $data['session_handler'] == 'database') + { + $table = JTable::getInstance('session'); + $table->purge(-1); + } + + if (empty($data['cache_handler'])) + { + $data['caching'] = 0; + } + + // Clean the cache if disabled but previously enabled. + if (!$data['caching'] && $prev['caching']) + { + $cache = JFactory::getCache(); + $cache->clean(); + } + + // Create the new configuration object. + $config = new JRegistry('config'); + $config->loadArray($data); + + // Overwrite the old FTP credentials with the new ones. + $temp = JFactory::getConfig(); + $temp->set('ftp_enable', $data['ftp_enable']); + $temp->set('ftp_host', $data['ftp_host']); + $temp->set('ftp_port', $data['ftp_port']); + $temp->set('ftp_user', $data['ftp_user']); + $temp->set('ftp_pass', $data['ftp_pass']); + $temp->set('ftp_root', $data['ftp_root']); + + // Clear cache of com_config component. + $this->cleanCache('_system'); + + // Write the configuration file. + return $this->writeConfigFile($config); + } + + /** + * Method to unset the root_user value from configuration data. + * + * This method will load the global configuration data straight from + * JConfig and remove the root_user value for security, then save the configuration. + * + * @since 1.6 + */ + public function removeroot() + { + // Get the previous configuration. + $prev = new JConfig; + $prev = JArrayHelper::fromObject($prev); + + // Create the new configuration object, and unset the root_user property + $config = new JRegistry('config'); + unset($prev['root_user']); + $config->loadArray($prev); + + // Write the configuration file. + return $this->writeConfigFile($config); + } + + /** + * Method to write the configuration to a file. + * + * @param JRegistry $config A JRegistry object containing all global config data. + * + * @return bool True on success, false on failure. + * + * @since 2.5.4 + */ + private function writeConfigFile(JRegistry $config) + { + jimport('joomla.filesystem.path'); + jimport('joomla.filesystem.file'); + + // Set the configuration file path. + $file = JPATH_CONFIGURATION . '/configuration.php'; + + // Get the new FTP credentials. + $ftp = JClientHelper::getCredentials('ftp', true); + + // Attempt to make the file writeable if using FTP. + if (!$ftp['enabled'] && JPath::isOwner($file) && !JPath::setPermissions($file, '0644')) + { + JError::raiseNotice('SOME_ERROR_CODE', JText::_('COM_CONFIG_ERROR_CONFIGURATION_PHP_NOTWRITABLE')); + } + + // Attempt to write the configuration file as a PHP class named JConfig. + $configuration = $config->toString('PHP', array('class' => 'JConfig', 'closingtag' => false)); + if (!JFile::write($file, $configuration)) + { + $this->setError(JText::_('COM_CONFIG_ERROR_WRITE_FAILED')); + return false; + } + + // Attempt to make the file unwriteable if using FTP. + if (!$ftp['enabled'] && JPath::isOwner($file) && !JPath::setPermissions($file, '0444')) + { + JError::raiseNotice('SOME_ERROR_CODE', JText::_('COM_CONFIG_ERROR_CONFIGURATION_PHP_NOTUNWRITABLE')); + } + + return true; + } +} diff --git a/administrator/components/com_config/models/component.php b/administrator/components/com_config/models/component.php new file mode 100644 index 0000000..efd24f6 --- /dev/null +++ b/administrator/components/com_config/models/component.php @@ -0,0 +1,217 @@ +input; + + // Set the component (option) we are dealing with. + $component = $input->get('component'); + $this->setState('component.option', $component); + + // Set an alternative path for the configuration file. + if ($path = $input->getString('path')) + { + $path = JPath::clean(JPATH_SITE . '/' . $path); + JPath::check($path); + $this->setState('component.path', $path); + } + } + + /** + * Method to get a form object. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * + * @return mixed A JForm object on success, false on failure + * + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + if ($path = $this->getState('component.path')) + { + // Add the search path for the admin component config.xml file. + JForm::addFormPath($path); + } + else + { + // Add the search path for the admin component config.xml file. + JForm::addFormPath(JPATH_ADMINISTRATOR . '/components/' . $this->getState('component.option')); + } + + // Get the form. + $form = $this->loadForm( + 'com_config.component', + 'config', + array('control' => 'jform', 'load_data' => $loadData), + false, + '/config' + ); + + if (empty($form)) + { + return false; + } + + return $form; + } + + /** + * Get the component information. + * + * @return object + * + * @since 1.6 + */ + function getComponent() + { + $option = $this->getState('component.option'); + + // Load common and local language files. + $lang = JFactory::getLanguage(); + $lang->load($option, JPATH_BASE, null, false, false) + || $lang->load($option, JPATH_BASE . "/components/$option", null, false, false) + || $lang->load($option, JPATH_BASE, $lang->getDefault(), false, false) + || $lang->load($option, JPATH_BASE . "/components/$option", $lang->getDefault(), false, false); + + $result = JComponentHelper::getComponent($option); + + $this->preprocessData('com_config.component', $result); + + return $result; + } + + /** + * Method to save the configuration data. + * + * @param array $data An array containing all global config data. + * + * @return bool True on success, false on failure. + * + * @since 1.6 + */ + public function save($data) + { + $dispatcher = JDispatcher::getInstance(); + $table = JTable::getInstance('extension'); + $isNew = true; + + // Save the rules. + if (isset($data['params']) && isset($data['params']['rules'])) + { + $rules = new JAccessRules($data['params']['rules']); + $asset = JTable::getInstance('asset'); + + if (!$asset->loadByName($data['option'])) + { + $root = JTable::getInstance('asset'); + $root->loadByName('root.1'); + $asset->name = $data['option']; + $asset->title = $data['option']; + $asset->setLocation($root->id, 'last-child'); + } + $asset->rules = (string) $rules; + + if (!$asset->check() || !$asset->store()) + { + $this->setError($asset->getError()); + return false; + } + + // We don't need this anymore + unset($data['option']); + unset($data['params']['rules']); + } + + // Load the previous Data + if (!$table->load($data['id'])) + { + $this->setError($table->getError()); + return false; + } + + unset($data['id']); + + // Bind the data. + if (!$table->bind($data)) + { + $this->setError($table->getError()); + return false; + } + + // Check the data. + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // Trigger the onConfigurationBeforeSave event. + $result = $dispatcher->trigger($this->event_before_save, array($this->option . '.' . $this->name, $table, $isNew)); + + if (in_array(false, $result, true)) + { + $this->setError($table->getError()); + return false; + } + + // Store the data. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Clean the component cache. + $this->cleanCache('_system'); + + // Trigger the onConfigurationAfterSave event. + $dispatcher->trigger($this->event_after_save, array($this->option . '.' . $this->name, $table, $isNew)); + + return true; + } +} diff --git a/administrator/components/com_config/models/fields/filters.php b/administrator/components/com_config/models/fields/filters.php new file mode 100644 index 0000000..f5964cb --- /dev/null +++ b/administrator/components/com_config/models/fields/filters.php @@ -0,0 +1,136 @@ +getUserGroups(); + // Build the form control. + $html = array(); + + // Open the table. + $html[] = ''; + + // The table heading. + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + + // The table body. + $html[] = ' '; + + foreach ($groups as $group) + { + if (!isset($this->value[$group->value])) + { + $this->value[$group->value] = array('filter_type' => 'BL', 'filter_tags' => '', 'filter_attributes' => ''); + } + $group_filter = $this->value[$group->value]; + + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + } + $html[] = ' '; + + // Close the table. + $html[] = '
'; + $html[] = ' ' . JText::_('JGLOBAL_FILTER_GROUPS_LABEL') . ''; + $html[] = ' '; + $html[] = ' ' . JText::_('JGLOBAL_FILTER_TYPE_LABEL') . ''; + $html[] = ' '; + $html[] = ' ' . JText::_('JGLOBAL_FILTER_TAGS_LABEL') . ''; + $html[] = ' '; + $html[] = ' ' . JText::_('JGLOBAL_FILTER_ATTRIBUTES_LABEL') . ''; + $html[] = '
'; + $html[] = ' ' . str_repeat('|—', $group->level) . $group->text; + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + $html[] = ' '; + $html[] = '
'; + + // Add notes + $html[] = '
'; + $html[] = '

' . JText::_('JGLOBAL_FILTER_TYPE_DESC') . '

'; + $html[] = '

' . JText::_('JGLOBAL_FILTER_TAGS_DESC') . '

'; + $html[] = '

' . JText::_('JGLOBAL_FILTER_ATTRIBUTES_DESC') . '

'; + $html[] = '
'; + + return implode("\n", $html); + } + + /** + * A helper to get the list of user groups. + * + * @return array + * + * @since 1.6 + */ + protected function getUserGroups() + { + // Get a database object. + $db = JFactory::getDbo(); + // Get the user groups from the database. + $query = $db->getQuery(true) + ->select('a.id AS value, a.title AS text, COUNT(DISTINCT b.id) AS level') + ->from('#__usergroups AS a') + ->join('LEFT', '#__usergroups AS b on a.lft > b.lft AND a.rgt < b.rgt') + ->group('a.id, a.title, a.lft') + ->order('a.lft ASC'); + $db->setQuery($query); + $options = $db->loadObjectList(); + + return $options; + } +} diff --git a/administrator/components/com_config/models/fields/index.html b/administrator/components/com_config/models/fields/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_config/models/fields/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_config/models/forms/application.xml b/administrator/components/com_config/models/forms/application.xml new file mode 100644 index 0000000..f9d3b94 --- /dev/null +++ b/administrator/components/com_config/models/forms/application.xml @@ -0,0 +1,800 @@ + +
+
+ + + + + + + + + +
+ +
+ + + + + + + + + + + + + +
+ +
+ + + + + + + + + + +
+ +
+ + + + + + + + + +
+ +
+ + + + + + + + + + + + + + +
+ +
+ + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + +
+ +
+ + + + + + + + + + + + + + +
+ +
+ + +
+ +
+ +
+
diff --git a/administrator/components/com_config/models/forms/index.html b/administrator/components/com_config/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_config/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_config/models/index.html b/administrator/components/com_config/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_config/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_config/views/application/index.html b/administrator/components/com_config/views/application/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_config/views/application/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_config/views/application/tmpl/default.php b/administrator/components/com_config/views/application/tmpl/default.php new file mode 100644 index 0000000..0fbbf87 --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default.php @@ -0,0 +1,114 @@ + + + +
+
+ + + + +
+ 'page-site')); ?> + + +
+
+ loadTemplate('site'); ?> + loadTemplate('metadata'); ?> +
+
+ loadTemplate('seo'); ?> + loadTemplate('cookie'); ?> +
+
+ + + +
+
+ loadTemplate('system'); ?> + loadTemplate('debug'); ?> +
+
+ loadTemplate('cache'); ?> + loadTemplate('session'); ?> +
+
+ + + +
+
+ loadTemplate('server'); ?> + loadTemplate('locale'); ?> + loadTemplate('ftp'); ?> +
+
+ loadTemplate('database'); ?> + loadTemplate('mail'); ?> +
+
+ + + +
+ loadTemplate('permissions'); ?> +
+ + + +
+ loadTemplate('filters'); ?> +
+ + + ftp) : ?> + + loadTemplate('ftplogin'); ?> + + + + + + + +
+ +
+
diff --git a/administrator/components/com_config/views/application/tmpl/default_cache.php b/administrator/components/com_config/views/application/tmpl/default_cache.php new file mode 100644 index 0000000..89bbab8 --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_cache.php @@ -0,0 +1,23 @@ +name = JText::_('COM_CONFIG_CACHE_SETTINGS'); +$this->fieldsname = 'cache'; +if (isset($this->data['cache_handler']) + && $this->data['cache_handler'] == 'memcache' + || $this->data['session_handler'] == 'memcache' + || $this->data['cache_handler'] == 'memcached' + || $this->data['session_handler'] == 'memcached' +) +{ + $this->fieldsname .= ',memcache'; +} +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_cookie.php b/administrator/components/com_config/views/application/tmpl/default_cookie.php new file mode 100644 index 0000000..2e8ad20 --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_cookie.php @@ -0,0 +1,14 @@ +name = JText::_('COM_CONFIG_COOKIE_SETTINGS'); +$this->fieldsname = 'cookie'; +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_database.php b/administrator/components/com_config/views/application/tmpl/default_database.php new file mode 100644 index 0000000..b4c39df --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_database.php @@ -0,0 +1,14 @@ +name = JText::_('COM_CONFIG_DATABASE_SETTINGS'); +$this->fieldsname = 'database'; +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_debug.php b/administrator/components/com_config/views/application/tmpl/default_debug.php new file mode 100644 index 0000000..2e6196a --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_debug.php @@ -0,0 +1,14 @@ +name = JText::_('COM_CONFIG_DEBUG_SETTINGS'); +$this->fieldsname = 'debug'; +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_filters.php b/administrator/components/com_config/views/application/tmpl/default_filters.php new file mode 100644 index 0000000..ab9d344 --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_filters.php @@ -0,0 +1,15 @@ +name = JText::_('COM_CONFIG_TEXT_FILTER_SETTINGS'); +$this->fieldsname = 'filters'; +$this->description = JText::_('COM_CONFIG_TEXT_FILTERS_DESC'); +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_ftp.php b/administrator/components/com_config/views/application/tmpl/default_ftp.php new file mode 100644 index 0000000..67f231a --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_ftp.php @@ -0,0 +1,14 @@ +name = JText::_('COM_CONFIG_FTP_SETTINGS'); +$this->fieldsname = 'ftp'; +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_ftplogin.php b/administrator/components/com_config/views/application/tmpl/default_ftplogin.php new file mode 100644 index 0000000..625ad80 --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_ftplogin.php @@ -0,0 +1,30 @@ + +
+ + + ftp instanceof Exception) : ?> +

ftp->message); ?>

+ +
+
+
+ +
+
+
+
+
+ +
+
+
diff --git a/administrator/components/com_config/views/application/tmpl/default_locale.php b/administrator/components/com_config/views/application/tmpl/default_locale.php new file mode 100644 index 0000000..f875d10 --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_locale.php @@ -0,0 +1,14 @@ +name = JText::_('COM_CONFIG_LOCATION_SETTINGS'); +$this->fieldsname = 'locale'; +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_mail.php b/administrator/components/com_config/views/application/tmpl/default_mail.php new file mode 100644 index 0000000..5f47ee6 --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_mail.php @@ -0,0 +1,14 @@ +name = JText::_('COM_CONFIG_MAIL_SETTINGS'); +$this->fieldsname = 'mail'; +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_metadata.php b/administrator/components/com_config/views/application/tmpl/default_metadata.php new file mode 100644 index 0000000..a6ffd4d --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_metadata.php @@ -0,0 +1,14 @@ +name = JText::_('COM_CONFIG_METADATA_SETTINGS'); +$this->fieldsname = 'metadata'; +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_navigation.php b/administrator/components/com_config/views/application/tmpl/default_navigation.php new file mode 100644 index 0000000..296aad9 --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_navigation.php @@ -0,0 +1,26 @@ + + diff --git a/administrator/components/com_config/views/application/tmpl/default_permissions.php b/administrator/components/com_config/views/application/tmpl/default_permissions.php new file mode 100644 index 0000000..6855183 --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_permissions.php @@ -0,0 +1,16 @@ +name = JText::_('COM_CONFIG_PERMISSION_SETTINGS'); +$this->fieldsname = 'permissions'; +$this->formclass = 'form-vertical'; +$this->showlabel = false; +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_seo.php b/administrator/components/com_config/views/application/tmpl/default_seo.php new file mode 100644 index 0000000..a57edab --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_seo.php @@ -0,0 +1,14 @@ +name = JText::_('COM_CONFIG_SEO_SETTINGS'); +$this->fieldsname = 'seo'; +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_server.php b/administrator/components/com_config/views/application/tmpl/default_server.php new file mode 100644 index 0000000..3307f7e --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_server.php @@ -0,0 +1,14 @@ +name = JText::_('COM_CONFIG_SERVER_SETTINGS'); +$this->fieldsname = 'server'; +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_session.php b/administrator/components/com_config/views/application/tmpl/default_session.php new file mode 100644 index 0000000..0fdac2a --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_session.php @@ -0,0 +1,14 @@ +name = JText::_('COM_CONFIG_SESSION_SETTINGS'); +$this->fieldsname = 'session'; +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_site.php b/administrator/components/com_config/views/application/tmpl/default_site.php new file mode 100644 index 0000000..b3456ca --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_site.php @@ -0,0 +1,14 @@ +name = JText::_('COM_CONFIG_SITE_SETTINGS'); +$this->fieldsname = 'site'; +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/default_system.php b/administrator/components/com_config/views/application/tmpl/default_system.php new file mode 100644 index 0000000..c78d4fc --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/default_system.php @@ -0,0 +1,14 @@ +name = JText::_('COM_CONFIG_SYSTEM_SETTINGS'); +$this->fieldsname = 'system'; +echo JLayoutHelper::render('joomla.content.options_default', $this); diff --git a/administrator/components/com_config/views/application/tmpl/index.html b/administrator/components/com_config/views/application/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_config/views/application/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_config/views/application/view.html.php b/administrator/components/com_config/views/application/view.html.php new file mode 100644 index 0000000..c232818 --- /dev/null +++ b/administrator/components/com_config/views/application/view.html.php @@ -0,0 +1,90 @@ +get('Form'); + $data = $this->get('Data'); + $user = JFactory::getUser(); + + // Check for model errors. + if ($errors = $this->get('Errors')) + { + JError::raiseError(500, implode('
', $errors)); + return false; + } + + // Bind the form to the data. + if ($form && $data) + { + $form->bind($data); + } + + // Get the params for com_users. + $usersParams = JComponentHelper::getParams('com_users'); + + // Get the params for com_media. + $mediaParams = JComponentHelper::getParams('com_media'); + + // Load settings for the FTP layer. + $ftp = JClientHelper::setCredentialsFromRequest('ftp'); + + $this->form = &$form; + $this->data = &$data; + $this->ftp = &$ftp; + $this->usersParams = &$usersParams; + $this->mediaParams = &$mediaParams; + + $this->components = ConfigHelperComponent::getComponentsWithConfig(); + ConfigHelperComponent::loadLanguageForComponents($this->components); + + $this->userIsSuperAdmin = $user->authorise('core.admin'); + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + JToolbarHelper::title(JText::_('COM_CONFIG_GLOBAL_CONFIGURATION'), 'config.png'); + JToolbarHelper::apply('application.apply'); + JToolbarHelper::save('application.save'); + JToolbarHelper::divider(); + JToolbarHelper::cancel('application.cancel'); + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_SITE_GLOBAL_CONFIGURATION'); + } +} diff --git a/administrator/components/com_config/views/close/index.html b/administrator/components/com_config/views/close/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_config/views/close/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_config/views/close/view.html.php b/administrator/components/com_config/views/close/view.html.php new file mode 100644 index 0000000..5894ae9 --- /dev/null +++ b/administrator/components/com_config/views/close/view.html.php @@ -0,0 +1,32 @@ +addScriptDeclaration(' + window.parent.location.href=window.parent.location.href; + window.parent.SqueezeBox.close(); + '); + } +} diff --git a/administrator/components/com_config/views/component/index.html b/administrator/components/com_config/views/component/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_config/views/component/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_config/views/component/tmpl/default.php b/administrator/components/com_config/views/component/tmpl/default.php new file mode 100644 index 0000000..90e7e43 --- /dev/null +++ b/administrator/components/com_config/views/component/tmpl/default.php @@ -0,0 +1,77 @@ +getTemplate(); + +JHtml::_('behavior.formvalidation'); +JHtml::_('formbehavior.chosen', 'select'); +?> + +
+
+ + + +
+ +
+ form->getFieldsets(); ?> + $fieldSet) : ?> +
+ description) && !empty($fieldSet->description)) : ?> +

description); ?>

+ + form->getFieldset($name) as $field): ?> +
+ hidden && $name != "permissions") : ?> +
+ label; ?> +
+ +
controls"> + input; ?> +
+
+ +
+ +
+
+
+
+ + + + + +
+
+ diff --git a/administrator/components/com_config/views/component/tmpl/default_navigation.php b/administrator/components/com_config/views/component/tmpl/default_navigation.php new file mode 100644 index 0000000..a95a396 --- /dev/null +++ b/administrator/components/com_config/views/component/tmpl/default_navigation.php @@ -0,0 +1,31 @@ + + diff --git a/administrator/components/com_config/views/component/tmpl/index.html b/administrator/components/com_config/views/component/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_config/views/component/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_config/views/component/view.html.php b/administrator/components/com_config/views/component/view.html.php new file mode 100644 index 0000000..62f2a86 --- /dev/null +++ b/administrator/components/com_config/views/component/view.html.php @@ -0,0 +1,121 @@ + 'JHELP_COMPONENTS_BANNER_MANAGER_OPTIONS', + 'com_cache' => 'JHELP_COMPONENTS_CACHE_MANAGER_SETTINGS', + 'com_checkin' => 'JHELP_COMPONENTS_CHECK-IN_CONFIGURATION', + 'com_contact' => 'JHELP_COMPONENTS_CONTACT_MANAGER_OPTIONS', + 'com_content' => 'JHELP_COMPONENTS_ARTICLE_MANAGER_OPTIONS', + 'com_finder' => 'JHELP_COMPONENTS_SMART_SEARCH_CONFIGURATION', + 'com_installer' => 'JHELP_COMPONENTS_INSTALLER_CONFIGURATION', + 'com_joomlaupdate' => 'JHELP_COMPONENTS_JOOMLA_UPDATE_CONFIGURATION', + 'com_languages' => 'JHELP_COMPONENTS_LANGUAGE_MANAGER_OPTIONS', + 'com_media' => 'JHELP_COMPONENTS_MEDIA_MANAGER_OPTIONS', + 'com_menus' => 'JHELP_COMPONENTS_MENUS_CONFIGURATION', + 'com_messages' => 'JHELP_COMPONENTS_MESSAGES_CONFIGURATION', + 'com_modules' => 'JHELP_COMPONENTS_MODULE_MANAGER_OPTIONS', + 'com_newsfeeds' => 'JHELP_COMPONENTS_NEWS_FEED_MANAGER_OPTIONS', + 'com_plugins' => 'JHELP_COMPONENTS_PLUG-IN_MANAGER_OPTIONS', + 'com_redirect' => 'JHELP_COMPONENTS_REDIRECT_MANAGER_OPTIONS', + 'com_search' => 'JHELP_COMPONENTS_SEARCH_MANAGER_OPTIONS', + 'com_tags' => 'JHELP_COMPONENTS_TAGS_MANAGER_OPTIONS', + 'com_templates' => 'JHELP_COMPONENTS_TEMPLATE_MANAGER_OPTIONS', + 'com_users' => 'JHELP_COMPONENTS_USERS_CONFIGURATION', + 'com_weblinks' => 'JHELP_COMPONENTS_WEB_LINKS_MANAGER_OPTIONS', + ); + + /** + * Execute and display a template script. + * + * @param string $tpl The name of the template file to parse; automatically searches through the template paths. + * + * @return mixed A string if successful, otherwise a Error object. + * + * @since 1.5 + */ + public function display($tpl = null) + { + $form = $this->get('Form'); + $component = $this->get('Component'); + $user = JFactory::getUser(); + $app = JFactory::getApplication(); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + // Bind the form to the data. + if ($form && $component->params) + { + $form->bind($component->params); + } + + $this->form = &$form; + $this->component = &$component; + + $this->components = ConfigHelperComponent::getComponentsWithConfig(); + ConfigHelperComponent::loadLanguageForComponents($this->components); + + $this->userIsSuperAdmin = $user->authorise('core.admin'); + $this->currentComponent = JFactory::getApplication()->input->get('component'); + $this->return = $app->input->get('return', '', 'base64'); + + $this->addToolbar(); + parent::display($tpl); + $app->input->set('hidemainmenu', true); + } + + /** + * Add the page title and toolbar. + * + * @since 3.0 + */ + protected function addToolbar() + { + JToolbarHelper::title(JText::_($this->component->option . '_configuration'), 'config.png'); + JToolbarHelper::apply('component.apply'); + JToolbarHelper::save('component.save'); + JToolbarHelper::divider(); + JToolbarHelper::cancel('component.cancel'); + JToolbarHelper::divider(); + + // Get the correct help key for this screen + if (isset($this->helpScreenArray[$this->component->option])) + { + JToolbarHelper::help($this->helpScreenArray[$this->component->option]); + } + else + { + JToolbarHelper::help('JHELP_SITE_GLOBAL_CONFIGURATION'); + } + } +} diff --git a/administrator/components/com_config/views/index.html b/administrator/components/com_config/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_config/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/access.xml b/administrator/components/com_contact/access.xml new file mode 100644 index 0000000..1024ae5 --- /dev/null +++ b/administrator/components/com_contact/access.xml @@ -0,0 +1,19 @@ + + +
+ + + + + + + +
+
+ + + + + +
+
\ No newline at end of file diff --git a/administrator/components/com_contact/config.xml b/administrator/components/com_contact/config.xml new file mode 100644 index 0000000..93eacc8 --- /dev/null +++ b/administrator/components/com_contact/config.xml @@ -0,0 +1,807 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + +
+ +
diff --git a/administrator/components/com_contact/contact.php b/administrator/components/com_contact/contact.php new file mode 100644 index 0000000..e81a5fb --- /dev/null +++ b/administrator/components/com_contact/contact.php @@ -0,0 +1,19 @@ +authorise('core.manage', 'com_contact')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$controller = JControllerLegacy::getInstance('contact'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_contact/contact.xml b/administrator/components/com_contact/contact.xml new file mode 100644 index 0000000..4c4896e --- /dev/null +++ b/administrator/components/com_contact/contact.xml @@ -0,0 +1,71 @@ + + + com_contact + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + + GNU General Public License version 2 or later; see + LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_CONTACT_XML_DESCRIPTION + + + + sql/install.mysql.utf8.sql + + + + + sql/uninstall.mysql.utf8.sql + + + + + contact.php + controller.php + index.html + metadata.xml + router.php + helpers + models + views + + + language/en-GB.com_contact.ini + + + + com_contact + + + com_contact_contacts + com_contact_categories + + + access.xml + config.xml + contact.php + controller.php + index.html + controllers + elements + helpers + models + tables + views + + + language/en-GB.com_contact.ini + language/en-GB.com_contact.sys.ini + + + + diff --git a/administrator/components/com_contact/controller.php b/administrator/components/com_contact/controller.php new file mode 100644 index 0000000..72a867d --- /dev/null +++ b/administrator/components/com_contact/controller.php @@ -0,0 +1,58 @@ +input->get('view', 'contacts'); + $layout = $this->input->get('layout', 'default'); + $id = $this->input->getInt('id'); + + // Check for edit form. + if ($view == 'contact' && $layout == 'edit' && !$this->checkEditId('com_contact.edit.contact', $id)) { + + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_contact&view=contacts', false)); + + return false; + } + + parent::display(); + + return $this; + } +} diff --git a/administrator/components/com_contact/controllers/contact.php b/administrator/components/com_contact/controllers/contact.php new file mode 100644 index 0000000..4040b62 --- /dev/null +++ b/administrator/components/com_contact/controllers/contact.php @@ -0,0 +1,119 @@ +input->getInt('filter_category_id'), 'int'); + $allow = null; + + if ($categoryId) + { + // If the category has been passed in the URL check it. + $allow = $user->authorise('core.create', $this->option . '.category.' . $categoryId); + } + + if ($allow === null) + { + // In the absense of better information, revert to the component permissions. + return parent::allowAdd($data); + } + else + { + return $allow; + } + } + + /** + * Method override to check if you can edit an existing record. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowEdit($data = array(), $key = 'id') + { + $recordId = (int) isset($data[$key]) ? $data[$key] : 0; + $categoryId = 0; + + if ($recordId) + { + $categoryId = (int) $this->getModel()->getItem($recordId)->catid; + } + + if ($categoryId) + { + // The category has been set. Check the category permissions. + return JFactory::getUser()->authorise('core.edit', $this->option . '.category.' . $categoryId); + } + else + { + // Since there is no asset tracking, revert to the component permissions. + return parent::allowEdit($data, $key); + } + } + + /** + * Method to run batch operations. + * + * @param object $model The model. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 2.5 + */ + public function batch($model = null) + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Set the model + $model = $this->getModel('Contact', '', array()); + + // Preset the redirect + $this->setRedirect(JRoute::_('index.php?option=com_contact&view=contacts' . $this->getRedirectToListAppend(), false)); + + return parent::batch($model); + } + + /** + * Function that allows child controller access to model data after the data has been saved. + * + * @param JModelLegacy $model The data model object. + * @param array $validData The validated data. + * + * @return void + * @since 3.1 + */ + protected function postSaveHook(JModelLegacy $model, $validData = array()) + { + } +} diff --git a/administrator/components/com_contact/controllers/contacts.php b/administrator/components/com_contact/controllers/contacts.php new file mode 100644 index 0000000..163f6a4 --- /dev/null +++ b/administrator/components/com_contact/controllers/contacts.php @@ -0,0 +1,116 @@ +registerTask('unfeatured', 'featured'); + } + + /** + * Method to toggle the featured setting of a list of contacts. + * + * @return void + * @since 1.6 + */ + public function featured() + { + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $user = JFactory::getUser(); + $ids = $this->input->get('cid', array(), 'array'); + $values = array('featured' => 1, 'unfeatured' => 0); + $task = $this->getTask(); + $value = JArrayHelper::getValue($values, $task, 0, 'int'); + + // Get the model. + $model = $this->getModel(); + + // Access checks. + foreach ($ids as $i => $id) + { + $item = $model->getItem($id); + if (!$user->authorise('core.edit.state', 'com_contact.category.'.(int) $item->catid)) + { + // Prune items that you can't change. + unset($ids[$i]); + JError::raiseNotice(403, JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED')); + } + } + + if (empty($ids)) + { + JError::raiseWarning(500, JText::_('COM_CONTACT_NO_ITEM_SELECTED')); + } + else + { + // Publish the items. + if (!$model->featured($ids, $value)) + { + JError::raiseWarning(500, $model->getError()); + } + } + + $this->setRedirect('index.php?option=com_contact&view=contacts'); + } + + /** + * Proxy for getModel. + * + * @param string $name The name of the model. + * @param string $prefix The prefix for the PHP class name. + * + * @return JModel + * @since 1.6 + */ + public function getModel($name = 'Contact', $prefix = 'ContactModel', $config = array('ignore_request' => true)) + { + $model = parent::getModel($name, $prefix, $config); + + return $model; + } + + /** + * Function that allows child controller access to model data + * after the item has been deleted. + * + * @param JModelLegacy $model The data model object. + * @param integer $ids The array of ids for items being deleted. + * + * @return void + * + * @since 12.2 + */ + protected function postDeleteHook(JModelLegacy $model, $ids = null) + { + } + +} diff --git a/administrator/components/com_contact/controllers/index.html b/administrator/components/com_contact/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/helpers/contact.php b/administrator/components/com_contact/helpers/contact.php new file mode 100644 index 0000000..c614c43 --- /dev/null +++ b/administrator/components/com_contact/helpers/contact.php @@ -0,0 +1,89 @@ +set($action->name, $user->authorise($action->name, $assetName)); + } + + return $result; + } +} diff --git a/administrator/components/com_contact/helpers/html/contact.php b/administrator/components/com_contact/helpers/html/contact.php new file mode 100644 index 0000000..bb4c968 --- /dev/null +++ b/administrator/components/com_contact/helpers/html/contact.php @@ -0,0 +1,116 @@ + $associated) + { + $associations[$tag] = (int) $associated->id; + } + + // Get the associated contact items + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('c.id, c.name as title') + ->select('l.sef as lang_sef') + ->from('#__contact_details as c') + ->select('cat.title as category_title') + ->join('LEFT', '#__categories as cat ON cat.id=c.catid') + ->where('c.id IN (' . implode(',', array_values($associations)) . ')') + ->join('LEFT', '#__languages as l ON c.language=l.lang_code') + ->select('l.image') + ->select('l.title as language_title'); + $db->setQuery($query); + + try + { + $items = $db->loadObjectList('id'); + } + catch (runtimeException $e) + { + throw new Exception($e->getMessage(), 500); + + return false; + } + + if ($items) + { + foreach ($items as &$item) + { + $text = strtoupper($item->lang_sef); + $url = JRoute::_('index.php?option=com_contact&task=contact.edit&id=' . (int) $item->id); + $tooltipParts = array( + JHtml::_('image', 'mod_languages/' . $item->image . '.gif', + $item->language_title, + array('title' => $item->language_title), + true + ), + $item->title, + '(' . $item->category_title . ')' + ); + + $item->link = JHtml::_('tooltip', implode(' ', $tooltipParts), null, null, $text, $url, null, 'hasTooltip label label-association label-' . $item->lang_sef); + } + } + + $html = JLayoutHelper::render('joomla.content.associations', $items); + } + + return $html; + } + + /** + * @param int $value The featured value + * @param int $i + * @param bool $canChange Whether the value can be changed or not + * + * @return string The anchor tag to toggle featured/unfeatured contacts. + * @since 1.6 + */ + public static function featured($value = 0, $i, $canChange = true) + { + // Array of image, task, title, action + $states = array( + 0 => array('disabled.png', 'contacts.featured', 'COM_CONTACT_UNFEATURED', 'COM_CONTACT_TOGGLE_TO_FEATURE'), + 1 => array('featured.png', 'contacts.unfeatured', 'JFEATURED', 'COM_CONTACT_TOGGLE_TO_UNFEATURE'), + ); + $state = JArrayHelper::getValue($states, (int) $value, $states[1]); + $html = JHtml::_('image', 'admin/'.$state[0], JText::_($state[2]), null, true); + if ($canChange) + { + $html = '' + . $html .''; + } + + return $html; + } +} diff --git a/administrator/components/com_contact/helpers/html/index.html b/administrator/components/com_contact/helpers/html/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/helpers/html/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/helpers/index.html b/administrator/components/com_contact/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/index.html b/administrator/components/com_contact/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/models/contact.php b/administrator/components/com_contact/models/contact.php new file mode 100644 index 0000000..fea78ad --- /dev/null +++ b/administrator/components/com_contact/models/contact.php @@ -0,0 +1,749 @@ +setError(JText::_('JGLOBAL_NO_ITEM_SELECTED')); + return false; + } + + $done = false; + + if (!empty($commands['category_id'])) + { + $cmd = JArrayHelper::getValue($commands, 'move_copy', 'c'); + + if ($cmd == 'c') + { + $result = $this->batchCopy($commands['category_id'], $pks, $contexts); + if (is_array($result)) + { + $pks = $result; + } + else + { + return false; + } + } + elseif ($cmd == 'm' && !$this->batchMove($commands['category_id'], $pks, $contexts)) + { + return false; + } + $done = true; + } + + if (!empty($commands['assetgroup_id'])) + { + if (!$this->batchAccess($commands['assetgroup_id'], $pks, $contexts)) + { + return false; + } + + $done = true; + } + + if (!empty($commands['language_id'])) + { + if (!$this->batchLanguage($commands['language_id'], $pks, $contexts)) + { + return false; + } + + $done = true; + } + + if (!empty($commands['tag'])) + { + if (!$this->batchTag($commands['tag'], $pks, $contexts)) + { + return false; + } + + $done = true; + } + + if (strlen($commands['user_id']) > 0) + { + if (!$this->batchUser($commands['user_id'], $pks, $contexts)) + { + return false; + } + + $done = true; + } + + if (!$done) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_INSUFFICIENT_BATCH_INFORMATION')); + return false; + } + + // Clear the cache + $this->cleanCache(); + + return true; + } + + /** + * Batch copy items to a new category or current. + * + * @param integer $value The new category. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return mixed An array of new IDs on success, boolean false on failure. + * + * @since 11.1 + */ + protected function batchCopy($value, $pks, $contexts) + { + $categoryId = (int) $value; + + $table = $this->getTable(); + $i = 0; + + // Check that the category exists + if ($categoryId) + { + $categoryTable = JTable::getInstance('Category'); + if (!$categoryTable->load($categoryId)) + { + if ($error = $categoryTable->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND')); + return false; + } + } + } + + if (empty($categoryId)) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND')); + return false; + } + + // Check that the user has create permission for the component + $user = JFactory::getUser(); + if (!$user->authorise('core.create', 'com_contact.category.' . $categoryId)) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE')); + return false; + } + + // Parent exists so we let's proceed + while (!empty($pks)) + { + // Pop the first ID off the stack + $pk = array_shift($pks); + + $table->reset(); + + // Check that the row actually exists + if (!$table->load($pk)) + { + if ($error = $table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Not fatal error + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + } + + // Alter the title & alias + $data = $this->generateNewTitle($categoryId, $table->alias, $table->name); + $table->name = $data['0']; + $table->alias = $data['1']; + + // Reset the ID because we are making a copy + $table->id = 0; + + // New category ID + $table->catid = $categoryId; + + // TODO: Deal with ordering? + //$table->ordering = 1; + + // Check the row. + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // Store the row. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Get the new item ID + $newId = $table->get('id'); + + // Add the new ID to the array + $newIds[$i] = $newId; + $i++; + } + + // Clean the cache + $this->cleanCache(); + + return $newIds; + } + + /** + * Batch change a linked user. + * + * @param integer $value The new value matching a User ID. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 2.5 + */ + protected function batchUser($value, $pks, $contexts) + { + // Set the variables + $user = JFactory::getUser(); + $table = $this->getTable(); + + foreach ($pks as $pk) + { + if ($user->authorise('core.edit', $contexts[$pk])) + { + $table->reset(); + $table->load($pk); + $table->user_id = (int) $value; + + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + } + else + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT')); + return false; + } + } + + // Clean the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to test whether a record can be deleted. + * + * @param object $record A record object. + * + * @return boolean True if allowed to delete the record. Defaults to the permission set in the component. + * @since 1.6 + */ + protected function canDelete($record) + { + if (!empty($record->id)) + { + if ($record->published != -2) + { + return; + } + $user = JFactory::getUser(); + return $user->authorise('core.delete', 'com_contact.category.' . (int) $record->catid); + } + } + + /** + * Method to test whether a record can have its state edited. + * + * @param object $record A record object. + * + * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. + * @since 1.6 + */ + protected function canEditState($record) + { + $user = JFactory::getUser(); + + // Check against the category. + if (!empty($record->catid)) + { + return $user->authorise('core.edit.state', 'com_contact.category.' . (int) $record->catid); + } + // Default to component settings if category not known. + else + { + return parent::canEditState($record); + } + } + + /** + * Returns a Table object, always creating it + * + * @param type $type The table type to instantiate + * @param string $prefix A prefix for the table class name. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return JTable A database object + * @since 1.6 + */ + public function getTable($type = 'Contact', $prefix = 'ContactTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Method to get the row form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * + * @return mixed A JForm object on success, false on failure + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + JForm::addFieldPath('JPATH_ADMINISTRATOR/components/com_users/models/fields'); + + // Get the form. + $form = $this->loadForm('com_contact.contact', 'contact', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + // Modify the form based on access controls. + if (!$this->canEditState((object) $data)) + { + // Disable fields for display. + $form->setFieldAttribute('featured', 'disabled', 'true'); + $form->setFieldAttribute('ordering', 'disabled', 'true'); + $form->setFieldAttribute('published', 'disabled', 'true'); + + // Disable fields while saving. + // The controller has already verified this is a record you can edit. + $form->setFieldAttribute('featured', 'filter', 'unset'); + $form->setFieldAttribute('ordering', 'filter', 'unset'); + $form->setFieldAttribute('published', 'filter', 'unset'); + } + + return $form; + } + + /** + * Method to get a single record. + * + * @param integer $pk The id of the primary key. + * + * @return mixed Object on success, false on failure. + * @since 1.6 + */ + public function getItem($pk = null) + { + if ($item = parent::getItem($pk)) + { + // Convert the metadata field to an array. + $registry = new JRegistry; + $registry->loadString($item->metadata); + $item->metadata = $registry->toArray(); + } + + // Load associated contact items + $app = JFactory::getApplication(); + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + + if ($assoc) + { + $item->associations = array(); + + if ($item->id != null) + { + $associations = JLanguageAssociations::getAssociations('com_contact', '#__contact_details', 'com_contact.item', $item->id); + + foreach ($associations as $tag => $association) + { + $item->associations[$tag] = $association->id; + } + } + } + + // Load item tags + if (!empty($item->id)) + { + $item->tags = new JHelperTags; + $item->tags->getTagIds($item->id, 'com_contact.contact'); + } + + return $item; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_contact.edit.contact.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + + // Prime some default values. + if ($this->getState('contact.id') == 0) + { + $app = JFactory::getApplication(); + $data->set('catid', $app->input->get('catid', $app->getUserState('com_contact.contacts.filter.category_id'), 'int')); + } + } + + $this->preprocessData('com_contact.contact', $data); + + return $data; + } + + /** + * Method to save the form data. + * + * @param array The form data. + * + * @return boolean True on success. + * @since 3.0 + */ + public function save($data) + { + $app = JFactory::getApplication(); + + // Alter the title for save as copy + if ($app->input->get('task') == 'save2copy') + { + list($name, $alias) = $this->generateNewTitle($data['catid'], $data['alias'], $data['name']); + $data['name'] = $name; + $data['alias'] = $alias; + $data['published'] = 0; + } + + $links = array('linka', 'linkb', 'linkc', 'linkd', 'linke'); + + foreach ($links as $link) + { + if ($data['params'][$link]) + { + $data['params'][$link] = JStringPunycode::urlToPunycode($data['params'][$link]); + } + } + + if (parent::save($data)) + { + + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $id = (int) $this->getState($this->getName() . '.id'); + $item = $this->getItem($id); + + // Adding self to the association + $associations = $data['associations']; + + foreach ($associations as $tag => $id) + { + if (empty($id)) + { + unset($associations[$tag]); + } + } + + // Detecting all item menus + $all_language = $item->language == '*'; + + if ($all_language && !empty($associations)) + { + JError::raiseNotice(403, JText::_('COM_CONTACT_ERROR_ALL_LANGUAGE_ASSOCIATED')); + } + + $associations[$item->language] = $item->id; + + // Deleting old association for these items + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->delete('#__associations') + ->where('context=' . $db->quote('com_contact.item')) + ->where('id IN (' . implode(',', $associations) . ')'); + $db->setQuery($query); + $db->execute(); + + if ($error = $db->getErrorMsg()) + { + $this->setError($error); + return false; + } + + if (!$all_language && count($associations)) + { + // Adding new association for these items + $key = md5(json_encode($associations)); + $query->clear() + ->insert('#__associations'); + + foreach ($associations as $id) + { + $query->values($id . ',' . $db->quote('com_contact.item') . ',' . $db->quote($key)); + } + + $db->setQuery($query); + $db->execute(); + + if ($error = $db->getErrorMsg()) + { + $this->setError($error); + return false; + } + } + } + + return true; + } + + return false; + } + + /** + * Prepare and sanitise the table prior to saving. + * + * @param JTable $table + * + * @return void + * @since 1.6 + */ + protected function prepareTable($table) + { + $date = JFactory::getDate(); + $user = JFactory::getUser(); + + $table->name = htmlspecialchars_decode($table->name, ENT_QUOTES); + $table->alias = JApplication::stringURLSafe($table->alias); + + if (empty($table->alias)) + { + $table->alias = JApplication::stringURLSafe($table->name); + } + + if (empty($table->id)) + { + // Set the values + $table->created = $date->toSql(); + + // Set ordering to the last item if not set + if (empty($table->ordering)) + { + $db = JFactory::getDbo(); + $db->setQuery('SELECT MAX(ordering) FROM #__contact_details'); + $max = $db->loadResult(); + + $table->ordering = $max + 1; + } + } + else + { + // Set the values + $table->modified = $date->toSql(); + $table->modified_by = $user->get('id'); + } + // Increment the content version number. + $table->version++; + } + + /** + * A protected method to get a set of ordering conditions. + * + * @param JTable $table A record object. + * + * @return array An array of conditions to add to add to ordering queries. + * @since 1.6 + */ + protected function getReorderConditions($table) + { + $condition = array(); + $condition[] = 'catid = ' . (int) $table->catid; + + return $condition; + } + + protected function preprocessForm(JForm $form, $data, $group = 'content') + { + // Association content items + $app = JFactory::getApplication(); + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $languages = JLanguageHelper::getLanguages('lang_code'); + + // force to array (perhaps move to $this->loadFormData()) + $data = (array) $data; + + $addform = new SimpleXMLElement('
'); + $fields = $addform->addChild('fields'); + $fields->addAttribute('name', 'associations'); + $fieldset = $fields->addChild('fieldset'); + $fieldset->addAttribute('name', 'item_associations'); + $fieldset->addAttribute('description', 'COM_CONTACT_ITEM_ASSOCIATIONS_FIELDSET_DESC'); + $add = false; + foreach ($languages as $tag => $language) + { + if (empty($data['language']) || $tag != $data['language']) + { + $add = true; + $field = $fieldset->addChild('field'); + $field->addAttribute('name', $tag); + $field->addAttribute('type', 'modal_contact'); + $field->addAttribute('language', $tag); + $field->addAttribute('label', $language->title); + $field->addAttribute('translate_label', 'false'); + $field->addAttribute('edit', 'true'); + $field->addAttribute('clear', 'true'); + } + } + if ($add) + { + $form->load($addform, false); + } + } + + parent::preprocessForm($form, $data, $group); + } + + /** + * Method to toggle the featured setting of contacts. + * + * @param array $pks The ids of the items to toggle. + * @param integer $value The value to toggle to. + * + * @return boolean True on success. + * @since 1.6 + */ + public function featured($pks, $value = 0) + { + // Sanitize the ids. + $pks = (array) $pks; + JArrayHelper::toInteger($pks); + + if (empty($pks)) + { + $this->setError(JText::_('COM_CONTACT_NO_ITEM_SELECTED')); + return false; + } + + $table = $this->getTable(); + + try + { + $db = $this->getDbo(); + + $db->setQuery( + 'UPDATE #__contact_details' . + ' SET featured = ' . (int) $value . + ' WHERE id IN (' . implode(',', $pks) . ')' + ); + $db->execute(); + } + catch (Exception $e) + { + $this->setError($e->getMessage()); + return false; + } + + $table->reorder(); + + // Clean component's cache + $this->cleanCache(); + + return true; + } + + /** + * Method to change the title & alias. + * + * @param integer $parent_id The id of the parent. + * @param string $alias The alias. + * @param string $title The title. + * + * @return array Contains the modified title and alias. + * + * @since 3.1 + */ + protected function generateNewTitle($category_id, $alias, $name) + { + // Alter the title & alias + $table = $this->getTable(); + while ($table->load(array('alias' => $alias, 'catid' => $category_id))) + { + if ($name == $table->name) + { + $name = JString::increment($name); + } + $alias = JString::increment($alias, 'dash'); + } + + return array($name, $alias); + } +} diff --git a/administrator/components/com_contact/models/contacts.php b/administrator/components/com_contact/models/contacts.php new file mode 100644 index 0000000..9b3dbc6 --- /dev/null +++ b/administrator/components/com_contact/models/contacts.php @@ -0,0 +1,281 @@ +item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $config['filter_fields'][] = 'association'; + } + } + + parent::__construct($config); + } + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @param string $ordering An optional ordering field. + * @param string $direction An optional direction (asc|desc). + * + * @return void + * + * @since 1.6 + */ + protected function populateState($ordering = null, $direction = null) + { + $app = JFactory::getApplication(); + + // Adjust the context to support modal layouts. + if ($layout = $app->input->get('layout')) + { + $this->context .= '.' . $layout; + } + + $search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $access = $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access', 0, 'int'); + $this->setState('filter.access', $access); + + $published = $this->getUserStateFromRequest($this->context . '.filter.published', 'filter_published', ''); + $this->setState('filter.published', $published); + + $categoryId = $this->getUserStateFromRequest($this->context . '.filter.category_id', 'filter_category_id'); + $this->setState('filter.category_id', $categoryId); + + $language = $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', ''); + $this->setState('filter.language', $language); + + // force a language + $forcedLanguage = $app->input->get('forcedLanguage'); + if (!empty($forcedLanguage)) + { + $this->setState('filter.language', $forcedLanguage); + $this->setState('filter.forcedLanguage', $forcedLanguage); + } + + $tag = $this->getUserStateFromRequest($this->context . '.filter.tag', 'filter_tag', ''); + $this->setState('filter.tag', $tag); + + // List state information. + parent::populateState('a.name', 'asc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + * @since 1.6 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.access'); + $id .= ':' . $this->getState('filter.published'); + $id .= ':' . $this->getState('filter.category_id'); + $id .= ':' . $this->getState('filter.language'); + + return parent::getStoreId($id); + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery + * @since 1.6 + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + $user = JFactory::getUser(); + $app = JFactory::getApplication(); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.id, a.name, a.alias, a.checked_out, a.checked_out_time, a.catid, a.user_id' . + ', a.published, a.access, a.created, a.created_by, a.ordering, a.featured, a.language' . + ', a.publish_up, a.publish_down' + ) + ); + $query->from('#__contact_details AS a'); + + // Join over the users for the linked user. + $query->select('ul.name AS linked_user') + ->join('LEFT', '#__users AS ul ON ul.id=a.user_id'); + + // Join over the language + $query->select('l.title AS language_title') + ->join('LEFT', $db->quoteName('#__languages') . ' AS l ON l.lang_code = a.language'); + + // Join over the users for the checked out user. + $query->select('uc.name AS editor') + ->join('LEFT', '#__users AS uc ON uc.id=a.checked_out'); + + // Join over the asset groups. + $query->select('ag.title AS access_level') + ->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access'); + + // Join over the categories. + $query->select('c.title AS category_title') + ->join('LEFT', '#__categories AS c ON c.id = a.catid'); + + // Join over the associations. + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $query->select('COUNT(asso2.id)>1 as association') + ->join('LEFT', '#__associations AS asso ON asso.id = a.id AND asso.context=' . $db->quote('com_contact.item')) + ->join('LEFT', '#__associations AS asso2 ON asso2.key = asso.key') + ->group('a.id'); + } + + // Filter by access level. + if ($access = $this->getState('filter.access')) + { + $query->where('a.access = ' . (int) $access); + } + + // Implement View Level Access + if (!$user->authorise('core.admin')) + { + $groups = implode(',', $user->getAuthorisedViewLevels()); + $query->where('a.access IN (' . $groups . ')'); + } + + // Filter by published state + $published = $this->getState('filter.published'); + if (is_numeric($published)) + { + $query->where('a.published = ' . (int) $published); + } + elseif ($published === '') + { + $query->where('(a.published = 0 OR a.published = 1)'); + } + + // Filter by a single or group of categories. + $categoryId = $this->getState('filter.category_id'); + if (is_numeric($categoryId)) + { + $query->where('a.catid = ' . (int) $categoryId); + } + elseif (is_array($categoryId)) + { + JArrayHelper::toInteger($categoryId); + $categoryId = implode(',', $categoryId); + $query->where('a.catid IN (' . $categoryId . ')'); + } + + // Filter by search in name. + $search = $this->getState('filter.search'); + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + elseif (stripos($search, 'author:') === 0) + { + $search = $db->quote('%' . $db->escape(substr($search, 7), true) . '%'); + $query->where('(uc.name LIKE ' . $search . ' OR uc.username LIKE ' . $search . ')'); + } + else + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('(a.name LIKE ' . $search . ' OR a.alias LIKE ' . $search . ')'); + } + } + + // Filter on the language. + if ($language = $this->getState('filter.language')) + { + $query->where('a.language = ' . $db->quote($language)); + } + + // Filter by a single tag. + $tagId = $this->getState('filter.tag'); + if (is_numeric($tagId)) + { + $query->where($db->quoteName('tagmap.tag_id') . ' = ' . (int) $tagId) + ->join( + 'LEFT', $db->quoteName('#__contentitem_tag_map', 'tagmap') + . ' ON ' . $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id') + . ' AND ' . $db->quoteName('tagmap.type_alias') . ' = ' . $db->quote('com_contact.contact') + ); + } + + // Add the list ordering clause. + $orderCol = $this->state->get('list.ordering', 'a.name'); + $orderDirn = $this->state->get('list.direction', 'asc'); + if ($orderCol == 'a.ordering' || $orderCol == 'category_title') + { + $orderCol = 'c.title ' . $orderDirn . ', a.ordering'; + } + $query->order($db->escape($orderCol . ' ' . $orderDirn)); + + //echo nl2br(str_replace('#__','jos_',$query)); + return $query; + } +} diff --git a/administrator/components/com_contact/models/fields/index.html b/administrator/components/com_contact/models/fields/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/models/fields/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/models/fields/modal/contact.php b/administrator/components/com_contact/models/fields/modal/contact.php new file mode 100644 index 0000000..06c622e --- /dev/null +++ b/administrator/components/com_contact/models/fields/modal/contact.php @@ -0,0 +1,162 @@ +element['edit'] == 'true') ? true : false; + $allowClear = ((string) $this->element['clear'] != 'false') ? true : false; + + // Load language + JFactory::getLanguage()->load('com_contact', JPATH_ADMINISTRATOR); + + // Load the javascript + JHtml::_('behavior.framework'); + JHtml::_('behavior.modal', 'a.modal'); + JHtml::_('bootstrap.tooltip'); + + // Build the script. + $script = array(); + + // Select button script + $script[] = ' function jSelectContact_'.$this->id.'(id, name, object) {'; + $script[] = ' document.id("'.$this->id.'_id").value = id;'; + $script[] = ' document.id("'.$this->id.'_name").value = name;'; + + if ($allowEdit) + { + $script[] = ' jQuery("#'.$this->id.'_edit").removeClass("hidden");'; + } + + if ($allowClear) + { + $script[] = ' jQuery("#'.$this->id.'_clear").removeClass("hidden");'; + } + + $script[] = ' SqueezeBox.close();'; + $script[] = ' }'; + + // Clear button script + static $scriptClear; + + if ($allowClear && !$scriptClear) + { + $scriptClear = true; + + $script[] = ' function jClearContact(id) {'; + $script[] = ' document.getElementById(id + "_id").value = "";'; + $script[] = ' document.getElementById(id + "_name").value = "'.htmlspecialchars(JText::_('COM_CONTACT_SELECT_A_CONTACT', true), ENT_COMPAT, 'UTF-8').'";'; + $script[] = ' jQuery("#"+id + "_clear").addClass("hidden");'; + $script[] = ' if (document.getElementById(id + "_edit")) {'; + $script[] = ' jQuery("#"+id + "_edit").addClass("hidden");'; + $script[] = ' }'; + $script[] = ' return false;'; + $script[] = ' }'; + } + + // Add the script to the document head. + JFactory::getDocument()->addScriptDeclaration(implode("\n", $script)); + + // Setup variables for display. + $html = array(); + $link = 'index.php?option=com_contact&view=contacts&layout=modal&tmpl=component&function=jSelectContact_'.$this->id; + + if (isset($this->element['language'])) + { + $link .= '&forcedLanguage='.$this->element['language']; + } + + // Get the title of the linked chart + $db = JFactory::getDbo(); + $db->setQuery( + 'SELECT name' . + ' FROM #__contact_details' . + ' WHERE id = '.(int) $this->value + ); + + try + { + $title = $db->loadResult(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage); + } + + if (empty($title)) + { + $title = JText::_('COM_CONTACT_SELECT_A_CONTACT'); + } + $title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); + + // The active contact id field. + if (0 == (int) $this->value) + { + $value = ''; + } + else + { + $value = (int) $this->value; + } + + // The current contact display field. + $html[] = ''; + $html[] = ''; + $html[] = ' '.JText::_('JSELECT').''; + + // Edit article button + if ($allowEdit) + { + $html[] = ' ' . JText::_('JACTION_EDIT') . ''; + } + + // Clear contact button + if ($allowClear) + { + $html[] = ''; + } + + $html[] = ''; + + // class='required' for client side validation + $class = ''; + if ($this->required) + { + $class = ' class="required modal-value"'; + } + + $html[] = ''; + + return implode("\n", $html); + } +} diff --git a/administrator/components/com_contact/models/fields/modal/index.html b/administrator/components/com_contact/models/fields/modal/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/models/fields/modal/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/models/fields/ordering.php b/administrator/components/com_contact/models/fields/ordering.php new file mode 100644 index 0000000..b370589 --- /dev/null +++ b/administrator/components/com_contact/models/fields/ordering.php @@ -0,0 +1,71 @@ +element['class'] ? ' class="'.(string) $this->element['class'].'"' : ''; + $attr .= ((string) $this->element['disabled'] == 'true') ? ' disabled="disabled"' : ''; + $attr .= $this->element['size'] ? ' size="'.(int) $this->element['size'].'"' : ''; + + // Initialize JavaScript field attributes. + $attr .= $this->element['onchange'] ? ' onchange="'.(string) $this->element['onchange'].'"' : ''; + + // Get some field values from the form. + $contactId = (int) $this->form->getValue('id'); + $categoryId = (int) $this->form->getValue('catid'); + + // Build the query for the ordering list. + $query = 'SELECT ordering AS value, name AS text' . + ' FROM #__contact_details' . + ' WHERE catid = ' . (int) $categoryId . + ' ORDER BY ordering'; + + // Create a read-only list (no name) with a hidden input to store the value. + if ((string) $this->element['readonly'] == 'true') + { + $html[] = JHtml::_('list.ordering', '', $query, trim($attr), $this->value, $contactId ? 0 : 1); + $html[] = ''; + } + // Create a regular list. + else { + $html[] = JHtml::_('list.ordering', $this->name, $query, trim($attr), $this->value, $contactId ? 0 : 1); + } + + return implode($html); + } +} diff --git a/administrator/components/com_contact/models/forms/contact.xml b/administrator/components/com_contact/models/forms/contact.xml new file mode 100644 index 0000000..6f5e6a5 --- /dev/null +++ b/administrator/components/com_contact/models/forms/contact.xml @@ -0,0 +1,736 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + + + + + + +
+
+ + + + diff --git a/administrator/components/com_contact/models/forms/index.html b/administrator/components/com_contact/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/models/index.html b/administrator/components/com_contact/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/sql/index.html b/administrator/components/com_contact/sql/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/sql/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/sql/install.mysql.utf8.sql b/administrator/components/com_contact/sql/install.mysql.utf8.sql new file mode 100644 index 0000000..fa7c2f5 --- /dev/null +++ b/administrator/components/com_contact/sql/install.mysql.utf8.sql @@ -0,0 +1,54 @@ +CREATE TABLE `#__contact_details` ( + `id` integer NOT NULL auto_increment, + `name` varchar(255) NOT NULL default '', + `alias` varchar(255) NOT NULL default '', + `con_position` varchar(255) default NULL, + `address` text, + `suburb` varchar(100) default NULL, + `state` varchar(100) default NULL, + `country` varchar(100) default NULL, + `postcode` varchar(100) default NULL, + `telephone` varchar(255) default NULL, + `fax` varchar(255) default NULL, + `misc` mediumtext, + `image` varchar(255) default NULL, + `imagepos` varchar(20) default NULL, + `email_to` varchar(255) default NULL, + `default_con` tinyint(1) unsigned NOT NULL default '0', + `published` tinyint(1) NOT NULL default '0', + `checked_out` integer unsigned NOT NULL default '0', + `checked_out_time` datetime NOT NULL default '0000-00-00 00:00:00', + `ordering` integer NOT NULL default '0', + `params` text NOT NULL, + `user_id` integer NOT NULL default '0', + `catid` integer NOT NULL default '0', + `access` tinyint(3) unsigned NOT NULL default '0', + `mobile` varchar(255) NOT NULL default '', + `webpage` varchar(255) NOT NULL default '', + `sortname1` varchar(255) NOT NULL, + `sortname2` varchar(255) NOT NULL, + `sortname3` varchar(255) NOT NULL, + `language` char(7) NOT NULL, + `created` datetime NOT NULL default '0000-00-00 00:00:00', + `created_by` int(10) unsigned NOT NULL default '0', + `created_by_alias` varchar(255) NOT NULL default '', + `modified` datetime NOT NULL default '0000-00-00 00:00:00', + `modified_by` int(10) unsigned NOT NULL default '0', + `metakey` text NOT NULL, + `metadesc` text NOT NULL, + `metadata` text NOT NULL, + `featured` tinyint(3) unsigned NOT NULL default '0' COMMENT 'Set if article is featured.', + `xreference` varchar(50) NOT NULL COMMENT 'A reference to enable linkages to external data sets.', + `publish_up` datetime NOT NULL default '0000-00-00 00:00:00', + `publish_down` datetime NOT NULL default '0000-00-00 00:00:00', + PRIMARY KEY (`id`), + KEY `idx_access` (`access`), + KEY `idx_checkout` (`checked_out`), + KEY `idx_state` (`published`), + KEY `idx_catid` (`catid`), + KEY `idx_createdby` (`created_by`), + KEY `idx_featured_catid` (`featured`,`catid`), + KEY `idx_language` (`language`), + KEY `idx_xreference` (`xreference`) +) DEFAULT CHARSET=utf8; + diff --git a/administrator/components/com_contact/sql/uninstall.mysql.utf8.sql b/administrator/components/com_contact/sql/uninstall.mysql.utf8.sql new file mode 100644 index 0000000..99de3fe --- /dev/null +++ b/administrator/components/com_contact/sql/uninstall.mysql.utf8.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS `#__contact_details`; + diff --git a/administrator/components/com_contact/tables/contact.php b/administrator/components/com_contact/tables/contact.php new file mode 100644 index 0000000..b42d52e --- /dev/null +++ b/administrator/components/com_contact/tables/contact.php @@ -0,0 +1,219 @@ +loadArray($array['params']); + $array['params'] = (string) $registry; + } + + if (isset($array['metadata']) && is_array($array['metadata'])) + { + $registry = new JRegistry; + $registry->loadArray($array['metadata']); + $array['metadata'] = (string) $registry; + } + + return parent::bind($array, $ignore); + } + + /** + * Stores a contact + * + * @param boolean True to update fields even if they are null. + * + * @return boolean True on success, false on failure. + * + * @since 1.6 + */ + public function store($updateNulls = false) + { + // Transform the params field + if (is_array($this->params)) + { + $registry = new JRegistry; + $registry->loadArray($this->params); + $this->params = (string) $registry; + } + + $date = JFactory::getDate(); + $user = JFactory::getUser(); + + if ($this->id) + { + // Existing item + $this->modified = $date->toSql(); + $this->modified_by = $user->get('id'); + } + else + { + // New contact. A contact created and created_by field can be set by the user, + // so we don't touch either of these if they are set. + if (!(int) $this->created) + { + $this->created = $date->toSql(); + } + if (empty($this->created_by)) + { + $this->created_by = $user->get('id'); + } + } + + // Set publish_up to null date if not set + if (!$this->publish_up) + { + $this->publish_up = $this->_db->getNullDate(); + } + + // Set publish_down to null date if not set + if (!$this->publish_down) + { + $this->publish_down = $this->_db->getNullDate(); + } + + // Set xreference to empty string if not set + if (!$this->xreference) + { + $this->xreference = ''; + } + + // Store utf8 email as punycode + $this->email_to = JStringPunycode::emailToPunycode($this->email_to); + + // Convert IDN urls to punycode + $this->webpage = JStringPunycode::urlToPunycode($this->webpage); + + // Verify that the alias is unique + $table = JTable::getInstance('Contact', 'ContactTable'); + if ($table->load(array('alias' => $this->alias, 'catid' => $this->catid)) && ($table->id != $this->id || $this->id == 0)) + { + $this->setError(JText::_('COM_CONTACT_ERROR_UNIQUE_ALIAS')); + + return false; + } + + return parent::store($updateNulls); + } + + /** + * Overloaded check function + * + * @return boolean True on success, false on failure + * + * @see JTable::check + * @since 1.5 + */ + public function check() + { + $this->default_con = (int) $this->default_con; + + if (JFilterInput::checkAttribute(array ('href', $this->webpage))) + { + $this->setError(JText::_('COM_CONTACT_WARNING_PROVIDE_VALID_URL')); + + return false; + } + + /** check for valid name */ + if (trim($this->name) == '') + { + $this->setError(JText::_('COM_CONTACT_WARNING_PROVIDE_VALID_NAME')); + + return false; + } + + if (empty($this->alias)) + { + $this->alias = $this->name; + } + $this->alias = JApplication::stringURLSafe($this->alias); + if (trim(str_replace('-', '', $this->alias)) == '') + { + $this->alias = JFactory::getDate()->format("Y-m-d-H-i-s"); + } + /** check for valid category */ + if (trim($this->catid) == '') + { + $this->setError(JText::_('COM_CONTACT_WARNING_CATEGORY')); + + return false; + } + + // Check the publish down date is not earlier than publish up. + if ((int) $this->publish_down > 0 && $this->publish_down < $this->publish_up) + { + $this->setError(JText::_('JGLOBAL_START_PUBLISH_AFTER_FINISH')); + + return false; + } + + return true; + + // Clean up keywords -- eliminate extra spaces between phrases + // and cr (\r) and lf (\n) characters from string + if (!empty($this->metakey)) + { + // Only process if not empty + $bad_characters = array("\n", "\r", "\"", "<", ">"); // array of characters to remove + $after_clean = JString::str_ireplace($bad_characters, "", $this->metakey); // remove bad characters + $keys = explode(',', $after_clean); // create array using commas as delimiter + $clean_keys = array(); + + foreach($keys as $key) + { + if (trim($key)) { // ignore blank keywords + $clean_keys[] = trim($key); + } + } + $this->metakey = implode(", ", $clean_keys); // put array back together delimited by ", " + } + + // Clean up description -- eliminate quotes and <> brackets + if (!empty($this->metadesc)) + { + // Only process if not empty + $bad_characters = array("\"", "<", ">"); + $this->metadesc = JString::str_ireplace($bad_characters, "", $this->metadesc); + } + + return true; + } +} diff --git a/administrator/components/com_contact/tables/index.html b/administrator/components/com_contact/tables/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/tables/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/views/contact/index.html b/administrator/components/com_contact/views/contact/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/views/contact/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/views/contact/tmpl/edit.php b/administrator/components/com_contact/views/contact/tmpl/edit.php new file mode 100644 index 0000000..4e3c670 --- /dev/null +++ b/administrator/components/com_contact/views/contact/tmpl/edit.php @@ -0,0 +1,215 @@ +input; + +$assoc = isset($app->item_associations) ? $app->item_associations : 0; +?> + + +
+ + + +
+ +
+
+ 'details')); ?> + + item->id) ? JText::_('COM_CONTACT_NEW_CONTACT', true) : JText::sprintf('COM_CONTACT_EDIT_CONTACT', $this->item->id, true)); ?> +
+
form->getLabel('name'); ?>
+
form->getInput('name'); ?>
+
+
+
form->getLabel('alias'); ?>
+
form->getInput('alias'); ?>
+
+
+
form->getLabel('user_id'); ?>
+
form->getInput('user_id'); ?>
+
+
+
form->getLabel('catid'); ?>
+
form->getInput('catid'); ?>
+
+
+
form->getLabel('ordering'); ?>
+
form->getInput('ordering'); ?>
+
+
+
form->getLabel('id'); ?>
+
form->getInput('id'); ?>
+
+
+ form->getLabel('misc'); ?> +
+ form->getInput('misc'); ?> + + + +
+
form->getLabel('created_by'); ?>
+
form->getInput('created_by'); ?>
+
+
+
form->getLabel('created_by_alias'); ?>
+
form->getInput('created_by_alias'); ?>
+
+
+
form->getLabel('created'); ?>
+
form->getInput('created'); ?>
+
+
+
form->getLabel('publish_up'); ?>
+
form->getInput('publish_up'); ?>
+
+
+
form->getLabel('publish_down'); ?>
+
form->getInput('publish_down'); ?>
+
+ item->modified_by) : ?> +
+
form->getLabel('modified_by'); ?>
+
form->getInput('modified_by'); ?>
+
+
+
form->getLabel('modified'); ?>
+
form->getInput('modified'); ?>
+
+ + item->version) : ?> +
+
+ form->getLabel('version'); ?> +
+
+ form->getInput('version'); ?> +
+
+ + item->hits) : ?> +
+
+ form->getLabel('hits'); ?> +
+
+ form->getInput('hits'); ?> +
+
+ + + + + +

item->id) ? JText::_('COM_CONTACT_DETAILS', true) : JText::sprintf('COM_CONTACT_EDIT_DETAILS', $this->item->id, true); ?>

+ +
+
form->getLabel('image'); ?>
+
form->getInput('image'); ?>
+
+
+
form->getLabel('con_position'); ?>
+
form->getInput('con_position'); ?>
+
+
+
form->getLabel('email_to'); ?>
+
form->getInput('email_to'); ?>
+
+
+
form->getLabel('address'); ?>
+
form->getInput('address'); ?>
+
+
+
form->getLabel('suburb'); ?>
+
form->getInput('suburb'); ?>
+
+
+
form->getLabel('state'); ?>
+
form->getInput('state'); ?>
+
+
+
form->getLabel('postcode'); ?>
+
form->getInput('postcode'); ?>
+
+
+
form->getLabel('country'); ?>
+
form->getInput('country'); ?>
+
+
+
form->getLabel('telephone'); ?>
+
form->getInput('telephone'); ?>
+
+
+
form->getLabel('mobile'); ?>
+
form->getInput('mobile'); ?>
+
+
+
form->getLabel('fax'); ?>
+
form->getInput('fax'); ?>
+
+
+
form->getLabel('webpage'); ?>
+
form->getInput('webpage'); ?>
+
+
+
form->getLabel('sortname1'); ?>
+
form->getInput('sortname1'); ?>
+
+
+
form->getLabel('sortname2'); ?>
+
form->getInput('sortname2'); ?>
+
+
+
form->getLabel('sortname3'); ?>
+
form->getInput('sortname3'); ?>
+
+ + + loadTemplate('params'); ?> + + + loadTemplate('metadata'); ?> + + + + + loadTemplate('associations'); ?> + + + + +
+ + +
+ + + + + diff --git a/administrator/components/com_contact/views/contact/tmpl/edit_associations.php b/administrator/components/com_contact/views/contact/tmpl/edit_associations.php new file mode 100644 index 0000000..7b50892 --- /dev/null +++ b/administrator/components/com_contact/views/contact/tmpl/edit_associations.php @@ -0,0 +1,12 @@ +form->getFieldsets('params'); +foreach ($fieldSets as $name => $fieldSet) : + $paramstabs = 'params-' . $name; + echo JHtml::_('bootstrap.addTab', 'myTab', $paramstabs, JText::_($fieldSet->label, true)); + + if (isset($fieldSet->description) && trim($fieldSet->description)) : + echo '

'.$this->escape(JText::_($fieldSet->description)).'

'; + endif; + ?> + form->getFieldset($name) as $field) : ?> +
+
label; ?>
+
input; ?>
+
+ + + diff --git a/administrator/components/com_contact/views/contact/tmpl/index.html b/administrator/components/com_contact/views/contact/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/views/contact/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/views/contact/tmpl/modal.php b/administrator/components/com_contact/views/contact/tmpl/modal.php new file mode 100644 index 0000000..8959e9c --- /dev/null +++ b/administrator/components/com_contact/views/contact/tmpl/modal.php @@ -0,0 +1,228 @@ +input; + +$assoc = isset($app->item_associations) ? $app->item_associations : 0; +?> + +
+ +
+ + + +
+ +
+
+ +
+
+ +
+
+ 'details')); ?> + + item->id) ? JText::_('COM_CONTACT_NEW_CONTACT', true) : JText::sprintf('COM_CONTACT_EDIT_CONTACT', $this->item->id, true)); ?> +
+
form->getLabel('name'); ?>
+
form->getInput('name'); ?>
+
+
+
form->getLabel('alias'); ?>
+
form->getInput('alias'); ?>
+
+
+
form->getLabel('user_id'); ?>
+
form->getInput('user_id'); ?>
+
+
+
form->getLabel('catid'); ?>
+
form->getInput('catid'); ?>
+
+
+
form->getLabel('ordering'); ?>
+
form->getInput('ordering'); ?>
+
+
+
form->getLabel('id'); ?>
+
form->getInput('id'); ?>
+
+
+ form->getLabel('misc'); ?> +
+ form->getInput('misc'); ?> + + + +
+
form->getLabel('created_by'); ?>
+
form->getInput('created_by'); ?>
+
+
+
form->getLabel('created_by_alias'); ?>
+
form->getInput('created_by_alias'); ?>
+
+
+
form->getLabel('created'); ?>
+
form->getInput('created'); ?>
+
+
+
form->getLabel('publish_up'); ?>
+
form->getInput('publish_up'); ?>
+
+
+
form->getLabel('publish_down'); ?>
+
form->getInput('publish_down'); ?>
+
+ item->modified_by) : ?> +
+
form->getLabel('modified_by'); ?>
+
form->getInput('modified_by'); ?>
+
+
+
form->getLabel('modified'); ?>
+
form->getInput('modified'); ?>
+
+ + item->version) : ?> +
+
+ form->getLabel('version'); ?> +
+
+ form->getInput('version'); ?> +
+
+ + item->hits) : ?> +
+
+ form->getLabel('hits'); ?> +
+
+ form->getInput('hits'); ?> +
+
+ + + + + +

item->id) ? JText::_('COM_CONTACT_DETAILS', true) : JText::sprintf('COM_CONTACT_EDIT_DETAILS', $this->item->id, true); ?>

+ +
+
form->getLabel('image'); ?>
+
form->getInput('image'); ?>
+
+
+
form->getLabel('con_position'); ?>
+
form->getInput('con_position'); ?>
+
+
+
form->getLabel('email_to'); ?>
+
form->getInput('email_to'); ?>
+
+
+
form->getLabel('address'); ?>
+
form->getInput('address'); ?>
+
+
+
form->getLabel('suburb'); ?>
+
form->getInput('suburb'); ?>
+
+
+
form->getLabel('state'); ?>
+
form->getInput('state'); ?>
+
+
+
form->getLabel('postcode'); ?>
+
form->getInput('postcode'); ?>
+
+
+
form->getLabel('country'); ?>
+
form->getInput('country'); ?>
+
+
+
form->getLabel('telephone'); ?>
+
form->getInput('telephone'); ?>
+
+
+
form->getLabel('mobile'); ?>
+
form->getInput('mobile'); ?>
+
+
+
form->getLabel('fax'); ?>
+
form->getInput('fax'); ?>
+
+
+
form->getLabel('webpage'); ?>
+
form->getInput('webpage'); ?>
+
+
+
form->getLabel('sortname1'); ?>
+
form->getInput('sortname1'); ?>
+
+
+
form->getLabel('sortname2'); ?>
+
form->getInput('sortname2'); ?>
+
+
+
form->getLabel('sortname3'); ?>
+
form->getInput('sortname3'); ?>
+
+ + + loadTemplate('params'); ?> + + + loadTemplate('metadata'); ?> + + + +
+ + + + +
+ + + + + +
\ No newline at end of file diff --git a/administrator/components/com_contact/views/contact/tmpl/modal_associations.php b/administrator/components/com_contact/views/contact/tmpl/modal_associations.php new file mode 100644 index 0000000..7b50892 --- /dev/null +++ b/administrator/components/com_contact/views/contact/tmpl/modal_associations.php @@ -0,0 +1,12 @@ +form->getFieldsets('params'); +foreach ($fieldSets as $name => $fieldSet) : + $paramstabs = 'params-' . $name; + echo JHtml::_('bootstrap.addTab', 'myTab', $paramstabs, JText::_($fieldSet->label, true)); + + if (isset($fieldSet->description) && trim($fieldSet->description)) : + echo '

'.$this->escape(JText::_($fieldSet->description)).'

'; + endif; + ?> + form->getFieldset($name) as $field) : ?> +
+
label; ?>
+
input; ?>
+
+ + + diff --git a/administrator/components/com_contact/views/contact/view.html.php b/administrator/components/com_contact/views/contact/view.html.php new file mode 100644 index 0000000..e2d82e4 --- /dev/null +++ b/administrator/components/com_contact/views/contact/view.html.php @@ -0,0 +1,116 @@ +form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + if ($this->getLayout() == 'modal') + { + $this->form->setFieldAttribute('language', 'readonly', 'true'); + $this->form->setFieldAttribute('catid', 'readonly', 'true'); + } + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + JFactory::getApplication()->input->set('hidemainmenu', true); + + $user = JFactory::getUser(); + $userId = $user->get('id'); + $isNew = ($this->item->id == 0); + $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $userId); + // Since we don't track these assets at the item level, use the category id. + $canDo = ContactHelper::getActions($this->item->catid, 0); + + JToolbarHelper::title(JText::_('COM_CONTACT_MANAGER_CONTACT'), 'contact.png'); + + // Build the actions for new and existing records. + if ($isNew) + { + // For new records, check the create permission. + if ($isNew && (count($user->getAuthorisedCategories('com_contact', 'core.create')) > 0)) + { + JToolbarHelper::apply('contact.apply'); + JToolbarHelper::save('contact.save'); + JToolbarHelper::save2new('contact.save2new'); + } + + JToolbarHelper::cancel('contact.cancel'); + } + else + { + // Can't save the record if it's checked out. + if (!$checkedOut) + { + // Since it's an existing record, check the edit permission, or fall back to edit own if the owner. + if ($canDo->get('core.edit') || ($canDo->get('core.edit.own') && $this->item->created_by == $userId)) + { + JToolbarHelper::apply('contact.apply'); + JToolbarHelper::save('contact.save'); + + // We can save this record, but check the create permission to see if we can return to make a new one. + if ($canDo->get('core.create')) + { + JToolbarHelper::save2new('contact.save2new'); + } + } + } + + // If checked out, we can still save + if ($canDo->get('core.create')) + { + JToolbarHelper::save2copy('contact.save2copy'); + } + + JToolbarHelper::cancel('contact.cancel', 'JTOOLBAR_CLOSE'); + } + + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_COMPONENTS_CONTACTS_CONTACTS_EDIT'); + } +} diff --git a/administrator/components/com_contact/views/contacts/index.html b/administrator/components/com_contact/views/contacts/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/views/contacts/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/views/contacts/tmpl/default.php b/administrator/components/com_contact/views/contacts/tmpl/default.php new file mode 100644 index 0000000..bc83a5d --- /dev/null +++ b/administrator/components/com_contact/views/contacts/tmpl/default.php @@ -0,0 +1,275 @@ +get('id'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$archived = $this->state->get('filter.published') == 2 ? true : false; +$trashed = $this->state->get('filter.published') == -2 ? true : false; +$canOrder = $user->authorise('core.edit.state', 'com_contact.category'); +$saveOrder = $listOrder == 'a.ordering'; +if ($saveOrder) +{ + $saveOrderingUrl = 'index.php?option=com_contact&task=contacts.saveOrderAjax&tmpl=component'; + JHtml::_('sortablelist.sortable', 'articleList', 'adminForm', strtolower($listDirn), $saveOrderingUrl); +} +$sortFields = $this->getSortFields(); +$assoc = isset($app->item_associations) ? $app->item_associations : 0; +?> + +
+sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ +
+ +
+ + +
+
+ + pagination->getLimitBox(); ?> +
+
+ + +
+
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + items); + foreach ($this->items as $i => $item) : + $ordering = $listOrder == 'a.ordering'; + $canCreate = $user->authorise('core.create', 'com_contact.category.'.$item->catid); + $canEdit = $user->authorise('core.edit', 'com_contact.category.'.$item->catid); + $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $userId || $item->checked_out == 0; + $canEditOwn = $user->authorise('core.edit.own', 'com_contact.category.'.$item->catid) && $item->created_by == $userId; + $canChange = $user->authorise('core.edit.state', 'com_contact.category.'.$item->catid) && $canCheckin; + + $item->cat_link = JRoute::_('index.php?option=com_categories&extension=com_contact&task=edit&type=other&id='.$item->catid); + ?> + + + + + + + + + + + + + + + + + + + + + +
+ ', 'a.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING'); ?> + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + id); ?> + + published, $i, 'contacts.', $canChange, 'cb', $item->publish_up, $item->publish_down); ?> + +
+ checked_out) : ?> + editor, $item->checked_out_time, 'contacts.', $canCheckin); ?> + + + + escape($item->name); ?> + + escape($item->name); ?> + + + escape($item->alias));?> + +
+ category_title; ?> +
+
+
+ id, 'contact.'); + JHtml::_('dropdown.divider'); + if ($item->published) : + JHtml::_('dropdown.unpublish', 'cb' . $i, 'contacts.'); + else : + JHtml::_('dropdown.publish', 'cb' . $i, 'contacts.'); + endif; + + if ($item->featured) : + JHtml::_('dropdown.unfeatured', 'cb' . $i, 'contacts.'); + else : + JHtml::_('dropdown.featured', 'cb' . $i, 'contacts.'); + endif; + + JHtml::_('dropdown.divider'); + + if ($archived) : + JHtml::_('dropdown.unarchive', 'cb' . $i, 'contacts.'); + else : + JHtml::_('dropdown.archive', 'cb' . $i, 'contacts.'); + endif; + + if ($item->checked_out) : + JHtml::_('dropdown.checkin', 'cb' . $i, 'contacts.'); + endif; + + if ($trashed) : + JHtml::_('dropdown.untrash', 'cb' . $i, 'contacts.'); + else : + JHtml::_('dropdown.trash', 'cb' . $i, 'contacts.'); + endif; + + // render dropdown list + echo JHtml::_('dropdown.render'); + ?> +
+
+ linked_user)) : ?> + linked_user;?> + + + featured, $i, $canChange); ?> + + access_level; ?> + + association) : ?> + id); ?> + + + language == '*'):?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + id; ?> +
+ pagination->getListFooter(); ?> +
+ + loadTemplate('batch'); ?> + + + + + + +
+ diff --git a/administrator/components/com_contact/views/contacts/tmpl/default_batch.php b/administrator/components/com_contact/views/contacts/tmpl/default_batch.php new file mode 100644 index 0000000..034e1f1 --- /dev/null +++ b/administrator/components/com_contact/views/contacts/tmpl/default_batch.php @@ -0,0 +1,57 @@ +state->get('filter.published'); +?> + diff --git a/administrator/components/com_contact/views/contacts/tmpl/index.html b/administrator/components/com_contact/views/contacts/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/views/contacts/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_contact/views/contacts/tmpl/modal.php b/administrator/components/com_contact/views/contacts/tmpl/modal.php new file mode 100644 index 0000000..89a5138 --- /dev/null +++ b/administrator/components/com_contact/views/contacts/tmpl/modal.php @@ -0,0 +1,160 @@ +input; +$function = $input->getCmd('function', 'jSelectContact'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +?> +
+
+
+
+ + +
+
+ + +
+
+
+
+ +
+ + + + + state->get('filter.forcedLanguage')) : ?> + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + items as $i => $item) : ?> + language && JLanguageMultilang::isEnabled()) + { + $tag = strlen($item->language); + if ($tag == 5) + { + $lang = substr($item->language, 0, 2); + } + elseif ($tag == 6) + { + $lang = substr($item->language, 0, 3); + } + else { + $lang = ""; + } + } + elseif (!JLanguageMultilang::isEnabled()) + { + $lang = ""; + } + ?> + + + + + + + + + + +
+ + + + + + + + + + + +
+ pagination->getListFooter(); ?> +
+ + escape($item->name); ?> + + linked_user)) : ?> + linked_user;?> + + + escape($item->access_level); ?> + + escape($item->category_title); ?> + + language == '*'):?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + id; ?> +
+ + + + + +
diff --git a/administrator/components/com_contact/views/contacts/view.html.php b/administrator/components/com_contact/views/contacts/view.html.php new file mode 100644 index 0000000..0bf8ef1 --- /dev/null +++ b/administrator/components/com_contact/views/contacts/view.html.php @@ -0,0 +1,177 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + ContactHelper::addSubmenu('contacts'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + // Preprocess the list of items to find ordering divisions. + // TODO: Complete the ordering stuff with nested sets + foreach ($this->items as &$item) + { + $item->order_up = true; + $item->order_dn = true; + } + + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + require_once JPATH_COMPONENT.'/helpers/contact.php'; + $canDo = ContactHelper::getActions($this->state->get('filter.category_id')); + $user = JFactory::getUser(); + // Get the toolbar object instance + $bar = JToolBar::getInstance('toolbar'); + + JToolbarHelper::title(JText::_('COM_CONTACT_MANAGER_CONTACTS'), 'contact.png'); + + if ($canDo->get('core.create') || (count($user->getAuthorisedCategories('com_contact', 'core.create'))) > 0) + { + JToolbarHelper::addNew('contact.add'); + } + + if (($canDo->get('core.edit')) || ($canDo->get('core.edit.own'))) + { + JToolbarHelper::editList('contact.edit'); + } + + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::publish('contacts.publish', 'JTOOLBAR_PUBLISH', true); + JToolbarHelper::unpublish('contacts.unpublish', 'JTOOLBAR_UNPUBLISH', true); + JToolbarHelper::archiveList('contacts.archive'); + JToolbarHelper::checkin('contacts.checkin'); + } + + if ($this->state->get('filter.published') == -2 && $canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'contacts.delete', 'JTOOLBAR_EMPTY_TRASH'); + } + elseif ($canDo->get('core.edit.state')) + { + JToolbarHelper::trash('contacts.trash'); + } + + // Add a batch button + if ($user->authorise('core.create', 'com_contacts') && $user->authorise('core.edit', 'com_contacts') && $user->authorise('core.edit.state', 'com_contacts')) + { + JHtml::_('bootstrap.modal', 'collapseModal'); + $title = JText::_('JTOOLBAR_BATCH'); + + // Instantiate a new JLayoutFile instance and render the batch button + $layout = new JLayoutFile('joomla.toolbar.batch'); + + $dhtml = $layout->render(array('title' => $title)); + $bar->appendButton('Custom', $dhtml, 'batch'); + } + + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_contact'); + } + + JToolbarHelper::help('JHELP_COMPONENTS_CONTACTS_CONTACTS'); + + JHtmlSidebar::setAction('index.php?option=com_contact'); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_published', + JHtml::_('select.options', JHtml::_('jgrid.publishedOptions'), 'value', 'text', $this->state->get('filter.published'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_CATEGORY'), + 'filter_category_id', + JHtml::_('select.options', JHtml::_('category.options', 'com_contact'), 'value', 'text', $this->state->get('filter.category_id')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_ACCESS'), + 'filter_access', + JHtml::_('select.options', JHtml::_('access.assetgroups'), 'value', 'text', $this->state->get('filter.access')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_LANGUAGE'), + 'filter_language', + JHtml::_('select.options', JHtml::_('contentlanguage.existing', true, true), 'value', 'text', $this->state->get('filter.language')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_TAG'), + 'filter_tag', + JHtml::_('select.options', JHtml::_('tag.options', true, true), 'value', 'text', $this->state->get('filter.tag')) + ); + + } + + /** + * Returns an array of fields the table can be sorted by + * + * @return array Array containing the field name to sort by as the key and display text as value + * + * @since 3.0 + */ + protected function getSortFields() + { + return array( + 'a.ordering' => JText::_('JGRID_HEADING_ORDERING'), + 'a.published' => JText::_('JSTATUS'), + 'a.name' => JText::_('JGLOBAL_TITLE'), + 'category_title' => JText::_('JCATEGORY'), + 'ul.name' => JText::_('COM_CONTACT_FIELD_LINKED_USER_LABEL'), + 'a.featured' => JText::_('JFEATURED'), + 'a.access' => JText::_('JGRID_HEADING_ACCESS'), + 'a.language' => JText::_('JGRID_HEADING_LANGUAGE'), + 'a.id' => JText::_('JGRID_HEADING_ID') + ); + } +} diff --git a/administrator/components/com_contact/views/index.html b/administrator/components/com_contact/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_contact/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/access.xml b/administrator/components/com_content/access.xml new file mode 100644 index 0000000..0686b83 --- /dev/null +++ b/administrator/components/com_content/access.xml @@ -0,0 +1,24 @@ + + +
+ + + + + + + +
+
+ + + + + +
+
+ + + +
+
\ No newline at end of file diff --git a/administrator/components/com_content/config.xml b/administrator/components/com_content/config.xml new file mode 100644 index 0000000..c540188 --- /dev/null +++ b/administrator/components/com_content/config.xml @@ -0,0 +1,930 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + +
+ +
+ + +
+
diff --git a/administrator/components/com_content/content.php b/administrator/components/com_content/content.php new file mode 100644 index 0000000..2708fcf --- /dev/null +++ b/administrator/components/com_content/content.php @@ -0,0 +1,21 @@ +authorise('core.manage', 'com_content')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +JLoader::register('ContentHelper', __DIR__ . '/helpers/content.php'); + +$controller = JControllerLegacy::getInstance('Content'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_content/content.xml b/administrator/components/com_content/content.xml new file mode 100644 index 0000000..13d5cac --- /dev/null +++ b/administrator/components/com_content/content.xml @@ -0,0 +1,45 @@ + + + com_content + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_CONTENT_XML_DESCRIPTION + + + content.php + controller.php + index.html + router.php + helpers + models + + + language/en-GB.com_content.ini + + + + access.xml + config.xml + content.php + controller.php + index.html + controllers + elements + helpers + models + tables + views + + + language/en-GB.com_content.ini + language/en-GB.com_content.sys.ini + + + + + diff --git a/administrator/components/com_content/controller.php b/administrator/components/com_content/controller.php new file mode 100644 index 0000000..25eb5ea --- /dev/null +++ b/administrator/components/com_content/controller.php @@ -0,0 +1,58 @@ +input->get('view', 'articles'); + $layout = $this->input->get('layout', 'articles'); + $id = $this->input->getInt('id'); + + // Check for edit form. + if ($view == 'article' && $layout == 'edit' && !$this->checkEditId('com_content.edit.article', $id)) + { + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_content&view=articles', false)); + + return false; + } + + parent::display(); + + return $this; + } +} diff --git a/administrator/components/com_content/controllers/article.php b/administrator/components/com_content/controllers/article.php new file mode 100644 index 0000000..1091a43 --- /dev/null +++ b/administrator/components/com_content/controllers/article.php @@ -0,0 +1,160 @@ +input->get('return') == 'featured') + { + $this->view_list = 'featured'; + $this->view_item = 'article&return=featured'; + } + } + + /** + * Method override to check if you can add a new record. + * + * @param array $data An array of input data. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowAdd($data = array()) + { + $user = JFactory::getUser(); + $categoryId = JArrayHelper::getValue($data, 'catid', $this->input->getInt('filter_category_id'), 'int'); + $allow = null; + + if ($categoryId) + { + // If the category has been passed in the data or URL check it. + $allow = $user->authorise('core.create', 'com_content.category.' . $categoryId); + } + + if ($allow === null) + { + // In the absense of better information, revert to the component permissions. + return parent::allowAdd(); + } + else + { + return $allow; + } + } + + /** + * Method override to check if you can edit an existing record. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowEdit($data = array(), $key = 'id') + { + $recordId = (int) isset($data[$key]) ? $data[$key] : 0; + $user = JFactory::getUser(); + $userId = $user->get('id'); + + // Check general edit permission first. + if ($user->authorise('core.edit', 'com_content.article.' . $recordId)) + { + return true; + } + + // Fallback on edit.own. + // First test if the permission is available. + if ($user->authorise('core.edit.own', 'com_content.article.' . $recordId)) + { + // Now test the owner is the user. + $ownerId = (int) isset($data['created_by']) ? $data['created_by'] : 0; + if (empty($ownerId) && $recordId) + { + // Need to do a lookup from the model. + $record = $this->getModel()->getItem($recordId); + + if (empty($record)) + { + return false; + } + + $ownerId = $record->created_by; + } + + // If the owner matches 'me' then do the test. + if ($ownerId == $userId) + { + return true; + } + } + + // Since there is no asset tracking, revert to the component permissions. + return parent::allowEdit($data, $key); + } + + /** + * Method to run batch operations. + * + * @param object $model The model. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 1.6 + */ + public function batch($model = null) + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Set the model + $model = $this->getModel('Article', '', array()); + + // Preset the redirect + $this->setRedirect(JRoute::_('index.php?option=com_content&view=articles' . $this->getRedirectToListAppend(), false)); + + return parent::batch($model); + } + + /** + * Function that allows child controller access to model data after the data has been saved. + * + * @param JModelLegacy $model The data model object. + * @param array $validData The validated data. + * + * @return void + * + * @since 3.1 + */ + protected function postSaveHook(JModelLegacy $model, $validData = array()) + { + + return; + } +} diff --git a/administrator/components/com_content/controllers/articles.php b/administrator/components/com_content/controllers/articles.php new file mode 100644 index 0000000..3142a5d --- /dev/null +++ b/administrator/components/com_content/controllers/articles.php @@ -0,0 +1,122 @@ +input->get('view') == 'featured') + { + $this->view_list = 'featured'; + } + + $this->registerTask('unfeatured', 'featured'); + } + + /** + * Method to toggle the featured setting of a list of articles. + * + * @return void + * @since 1.6 + */ + public function featured() + { + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $user = JFactory::getUser(); + $ids = $this->input->get('cid', array(), 'array'); + $values = array('featured' => 1, 'unfeatured' => 0); + $task = $this->getTask(); + $value = JArrayHelper::getValue($values, $task, 0, 'int'); + + // Access checks. + foreach ($ids as $i => $id) + { + if (!$user->authorise('core.edit.state', 'com_content.article.'.(int) $id)) + { + // Prune items that you can't change. + unset($ids[$i]); + JError::raiseNotice(403, JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED')); + } + } + + if (empty($ids)) + { + JError::raiseWarning(500, JText::_('JERROR_NO_ITEMS_SELECTED')); + } + else + { + // Get the model. + $model = $this->getModel(); + + // Publish the items. + if (!$model->featured($ids, $value)) + { + JError::raiseWarning(500, $model->getError()); + } + } + + $this->setRedirect('index.php?option=com_content&view=articles'); + } + + /** + * Proxy for getModel. + * + * @param string $name The name of the model. + * @param string $prefix The prefix for the PHP class name. + * + * @return JModel + * @since 1.6 + */ + public function getModel($name = 'Article', $prefix = 'ContentModel', $config = array('ignore_request' => true)) + { + $model = parent::getModel($name, $prefix, $config); + + return $model; + } + + /** + * Function that allows child controller access to model data + * after the item has been deleted. + * + * @param JModelLegacy $model The data model object. + * @param integer $ids The array of ids for items being deleted. + * + * @return void + * + * @since 12.2 + */ + protected function postDeleteHook(JModelLegacy $model, $ids = null) + { + } + +} diff --git a/administrator/components/com_content/controllers/featured.php b/administrator/components/com_content/controllers/featured.php new file mode 100644 index 0000000..2d1bb7d --- /dev/null +++ b/administrator/components/com_content/controllers/featured.php @@ -0,0 +1,90 @@ +input->get('cid', array(), 'array'); + + // Access checks. + foreach ($ids as $i => $id) + { + if (!$user->authorise('core.delete', 'com_content.article.'.(int) $id)) + { + // Prune items that you can't delete. + unset($ids[$i]); + JError::raiseNotice(403, JText::_('JERROR_CORE_DELETE_NOT_PERMITTED')); + } + } + + if (empty($ids)) + { + JError::raiseWarning(500, JText::_('JERROR_NO_ITEMS_SELECTED')); + } + else + { + // Get the model. + $model = $this->getModel(); + + // Remove the items. + if (!$model->featured($ids, 0)) + { + JError::raiseWarning(500, $model->getError()); + } + } + + $this->setRedirect('index.php?option=com_content&view=featured'); + } + + /** + * Method to publish a list of articles. + * + * @return void + * @since 1.0 + */ + public function publish() + { + parent::publish(); + + $this->setRedirect('index.php?option=com_content&view=featured'); + } + + /** + * Method to get a model object, loading it if required. + * + * @param string $name The model name. Optional. + * @param string $prefix The class prefix. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return object The model. + * + * @since 1.6 + */ + public function getModel($name = 'Feature', $prefix = 'ContentModel', $config = array('ignore_request' => true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } +} diff --git a/administrator/components/com_content/controllers/index.html b/administrator/components/com_content/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/helpers/content.php b/administrator/components/com_content/helpers/content.php new file mode 100644 index 0000000..54bd65d --- /dev/null +++ b/administrator/components/com_content/helpers/content.php @@ -0,0 +1,104 @@ +set($action, $user->authorise($action, $assetName)); + } + + return $result; + } + + /** + * Applies the content tag filters to arbitrary text as per settings for current user group + * + * @param text $text The string to filter + * + * @return string The filtered string + * + * @deprecated 4.0 Use JComponentHelper::filterText() instead. + */ + public static function filterText($text) + { + JLog::add('ContentHelper::filterText() is deprecated. Use JComponentHelper::filterText() instead.', JLog::WARNING, 'deprecated'); + + return JComponentHelper::filterText($text); + } +} diff --git a/administrator/components/com_content/helpers/html/contentadministrator.php b/administrator/components/com_content/helpers/html/contentadministrator.php new file mode 100644 index 0000000..b7cbff3 --- /dev/null +++ b/administrator/components/com_content/helpers/html/contentadministrator.php @@ -0,0 +1,126 @@ + $associated) + { + $associations[$tag] = (int) $associated->id; + } + + // Get the associated menu items + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('c.*') + ->select('l.sef as lang_sef') + ->from('#__content as c') + ->select('cat.title as category_title') + ->join('LEFT', '#__categories as cat ON cat.id=c.catid') + ->where('c.id IN (' . implode(',', array_values($associations)) . ')') + ->join('LEFT', '#__languages as l ON c.language=l.lang_code') + ->select('l.image') + ->select('l.title as language_title'); + $db->setQuery($query); + + try + { + $items = $db->loadObjectList('id'); + } + catch (RuntimeException $e) + { + throw new Exception($e->getMessage(), 500); + } + + if ($items) + { + foreach ($items as &$item) + { + $text = strtoupper($item->lang_sef); + $url = JRoute::_('index.php?option=com_content&task=article.edit&id=' . (int) $item->id); + $tooltipParts = array( + JHtml::_('image', 'mod_languages/' . $item->image . '.gif', + $item->language_title, + array('title' => $item->language_title), + true + ), + $item->title, + '(' . $item->category_title . ')' + ); + $item->link = JHtml::_('tooltip', implode(' ', $tooltipParts), null, null, $text, $url, null, 'hasTooltip label label-association label-' . $item->lang_sef); + } + } + + $html = JLayoutHelper::render('joomla.content.associations', $items); + } + + return $html; + } + + /** + * Show the feature/unfeature links + * + * @param int $value The state value + * @param int $i Row number + * @param boolean $canChange Is user allowed to change? + * + * @return string HTML code + */ + public static function featured($value = 0, $i, $canChange = true) + { + JHtml::_('bootstrap.tooltip'); + + // Array of image, task, title, action + $states = array( + 0 => array('unfeatured', 'articles.featured', 'COM_CONTENT_UNFEATURED', 'COM_CONTENT_TOGGLE_TO_FEATURE'), + 1 => array('featured', 'articles.unfeatured', 'COM_CONTENT_FEATURED', 'COM_CONTENT_TOGGLE_TO_UNFEATURE'), + ); + $state = JArrayHelper::getValue($states, (int) $value, $states[1]); + $icon = $state[0]; + + if ($canChange) + { + $html = ''; + } + else + { + $html = ''; + } + + return $html; + } +} diff --git a/administrator/components/com_content/helpers/html/index.html b/administrator/components/com_content/helpers/html/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/helpers/html/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/helpers/index.html b/administrator/components/com_content/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/index.html b/administrator/components/com_content/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/models/article.php b/administrator/components/com_content/models/article.php new file mode 100644 index 0000000..4b565ef --- /dev/null +++ b/administrator/components/com_content/models/article.php @@ -0,0 +1,725 @@ +getTable(); + $i = 0; + + // Check that the category exists + if ($categoryId) + { + $categoryTable = JTable::getInstance('Category'); + if (!$categoryTable->load($categoryId)) + { + if ($error = $categoryTable->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND')); + return false; + } + } + } + + if (empty($categoryId)) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND')); + return false; + } + + // Check that the user has create permission for the component + $extension = JFactory::getApplication()->input->get('option', ''); + $user = JFactory::getUser(); + if (!$user->authorise('core.create', $extension . '.category.' . $categoryId)) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE')); + return false; + } + + // Parent exists so we let's proceed + while (!empty($pks)) + { + // Pop the first ID off the stack + $pk = array_shift($pks); + + $table->reset(); + + // Check that the row actually exists + if (!$table->load($pk)) + { + if ($error = $table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Not fatal error + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + } + + // Alter the title & alias + $data = $this->generateNewTitle($categoryId, $table->alias, $table->title); + $table->title = $data['0']; + $table->alias = $data['1']; + + // Reset the ID because we are making a copy + $table->id = 0; + + // New category ID + $table->catid = $categoryId; + + // TODO: Deal with ordering? + //$table->ordering = 1; + + // Get the featured state + $featured = $table->featured; + + // Check the row. + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // Store the row. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Get the new item ID + $newId = $table->get('id'); + + // Add the new ID to the array + $newIds[$i] = $newId; + $i++; + + // Check if the article was featured and update the #__content_frontpage table + if ($featured == 1) + { + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->insert($db->quoteName('#__content_frontpage')) + ->values($newId . ', 0'); + $db->setQuery($query); + $db->execute(); + } + } + + // Clean the cache + $this->cleanCache(); + + return $newIds; + } + + /** + * Method to test whether a record can be deleted. + * + * @param object $record A record object. + * + * @return boolean True if allowed to delete the record. Defaults to the permission set in the component. + * @since 1.6 + */ + protected function canDelete($record) + { + if (!empty($record->id)) + { + if ($record->state != -2) + { + return; + } + $user = JFactory::getUser(); + return $user->authorise('core.delete', 'com_content.article.' . (int) $record->id); + } + } + + /** + * Method to test whether a record can have its state edited. + * + * @param object $record A record object. + * + * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. + * @since 1.6 + */ + protected function canEditState($record) + { + $user = JFactory::getUser(); + + // Check for existing article. + if (!empty($record->id)) + { + return $user->authorise('core.edit.state', 'com_content.article.' . (int) $record->id); + } + // New article, so check against the category. + elseif (!empty($record->catid)) + { + return $user->authorise('core.edit.state', 'com_content.category.' . (int) $record->catid); + } + // Default to component settings if neither article nor category known. + else + { + return parent::canEditState('com_content'); + } + } + + /** + * Prepare and sanitise the table data prior to saving. + * + * @param JTable A JTable object. + * + * @return void + * @since 1.6 + */ + protected function prepareTable($table) + { + // Set the publish date to now + $db = $this->getDbo(); + if ($table->state == 1 && (int) $table->publish_up == 0) + { + $table->publish_up = JFactory::getDate()->toSql(); + } + + if ($table->state == 1 && intval($table->publish_down) == 0) + { + $table->publish_down = $db->getNullDate(); + } + + // Increment the content version number. + $table->version++; + + // Reorder the articles within the category so the new article is first + if (empty($table->id)) + { + $table->reorder('catid = ' . (int) $table->catid . ' AND state >= 0'); + } + } + + /** + * Returns a Table object, always creating it. + * + * @param type The table type to instantiate + * @param string A prefix for the table class name. Optional. + * @param array Configuration array for model. Optional. + * + * @return JTable A database object + */ + public function getTable($type = 'Content', $prefix = 'JTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Method to get a single record. + * + * @param integer The id of the primary key. + * + * @return mixed Object on success, false on failure. + */ + public function getItem($pk = null) + { + if ($item = parent::getItem($pk)) + { + // Convert the params field to an array. + $registry = new JRegistry; + $registry->loadString($item->attribs); + $item->attribs = $registry->toArray(); + + // Convert the metadata field to an array. + $registry = new JRegistry; + $registry->loadString($item->metadata); + $item->metadata = $registry->toArray(); + + // Convert the images field to an array. + $registry = new JRegistry; + $registry->loadString($item->images); + $item->images = $registry->toArray(); + + // Convert the urls field to an array. + $registry = new JRegistry; + $registry->loadString($item->urls); + $item->urls = $registry->toArray(); + + $item->articletext = trim($item->fulltext) != '' ? $item->introtext . "
" . $item->fulltext : $item->introtext; + + if (!empty($item->id)) + { + $item->tags = new JHelperTags; + $item->tags->getTagIds($item->id, 'com_content.article'); + } + } + + // Load associated content items + $app = JFactory::getApplication(); + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + + if ($assoc) + { + $item->associations = array(); + + if ($item->id != null) + { + $associations = JLanguageAssociations::getAssociations('com_content', '#__content', 'com_content.item', $item->id); + + foreach ($associations as $tag => $association) + { + $item->associations[$tag] = $association->id; + } + } + } + + return $item; + } + + /** + * Method to get the record form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * + * @return mixed A JForm object on success, false on failure + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + // Get the form. + $form = $this->loadForm('com_content.article', 'article', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + $jinput = JFactory::getApplication()->input; + + // The front end calls this model and uses a_id to avoid id clashes so we need to check for that first. + if ($jinput->get('a_id')) + { + $id = $jinput->get('a_id', 0); + } + // The back end uses id so we use that the rest of the time and set it to 0 by default. + else + { + $id = $jinput->get('id', 0); + } + // Determine correct permissions to check. + if ($this->getState('article.id')) + { + $id = $this->getState('article.id'); + // Existing record. Can only edit in selected categories. + $form->setFieldAttribute('catid', 'action', 'core.edit'); + // Existing record. Can only edit own articles in selected categories. + $form->setFieldAttribute('catid', 'action', 'core.edit.own'); + } + else + { + // New record. Can only create in selected categories. + $form->setFieldAttribute('catid', 'action', 'core.create'); + } + + $user = JFactory::getUser(); + + // Check for existing article. + // Modify the form based on Edit State access controls. + if ($id != 0 && (!$user->authorise('core.edit.state', 'com_content.article.' . (int) $id)) + || ($id == 0 && !$user->authorise('core.edit.state', 'com_content')) + ) + { + // Disable fields for display. + $form->setFieldAttribute('featured', 'disabled', 'true'); + $form->setFieldAttribute('ordering', 'disabled', 'true'); + $form->setFieldAttribute('publish_up', 'disabled', 'true'); + $form->setFieldAttribute('publish_down', 'disabled', 'true'); + $form->setFieldAttribute('state', 'disabled', 'true'); + + // Disable fields while saving. + // The controller has already verified this is an article you can edit. + $form->setFieldAttribute('featured', 'filter', 'unset'); + $form->setFieldAttribute('ordering', 'filter', 'unset'); + $form->setFieldAttribute('publish_up', 'filter', 'unset'); + $form->setFieldAttribute('publish_down', 'filter', 'unset'); + $form->setFieldAttribute('state', 'filter', 'unset'); + } + + // Prevent messing with article language and category when editing existing article with associations + $app = JFactory::getApplication(); + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + + if ($app->isSite() && $assoc && $this->getState('article.id')) + { + $form->setFieldAttribute('language', 'readonly', 'true'); + $form->setFieldAttribute('catid', 'readonly', 'true'); + $form->setFieldAttribute('language', 'filter', 'unset'); + $form->setFieldAttribute('catid', 'filter', 'unset'); + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $app = JFactory::getApplication(); + $data = $app->getUserState('com_content.edit.article.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + + // Prime some default values. + if ($this->getState('article.id') == 0) + { + $data->set('catid', $app->input->getInt('catid', $app->getUserState('com_content.articles.filter.category_id'))); + } + } + + $this->preprocessData('com_content.article', $data); + + return $data; + } + + /** + * Method to save the form data. + * + * @param array The form data. + * + * @return boolean True on success. + * @since 1.6 + */ + public function save($data) + { + $app = JFactory::getApplication(); + + if (isset($data['images']) && is_array($data['images'])) + { + $registry = new JRegistry; + $registry->loadArray($data['images']); + $data['images'] = (string) $registry; + } + + if (isset($data['urls']) && is_array($data['urls'])) + { + + foreach ($data['urls'] as $i => $url) + { + if ($url != false && ($i == 'urla' || $i == 'urlb' || $i = 'urlc')) + { + $data['urls'][$i] = JStringPunycode::urlToPunycode($url); + } + + } + $registry = new JRegistry; + $registry->loadArray($data['urls']); + $data['urls'] = (string) $registry; + } + + // Alter the title for save as copy + if ($app->input->get('task') == 'save2copy') + { + list($title, $alias) = $this->generateNewTitle($data['catid'], $data['alias'], $data['title']); + $data['title'] = $title; + $data['alias'] = $alias; + $data['state'] = 0; + } + + if (parent::save($data)) + { + + if (isset($data['featured'])) + { + $this->featured($this->getState($this->getName() . '.id'), $data['featured']); + } + + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $id = (int) $this->getState($this->getName() . '.id'); + $item = $this->getItem($id); + + // Adding self to the association + $associations = $data['associations']; + + foreach ($associations as $tag => $id) + { + if (empty($id)) + { + unset($associations[$tag]); + } + } + + // Detecting all item menus + $all_language = $item->language == '*'; + + if ($all_language && !empty($associations)) + { + JError::raiseNotice(403, JText::_('COM_CONTENT_ERROR_ALL_LANGUAGE_ASSOCIATED')); + } + + $associations[$item->language] = $item->id; + + // Deleting old association for these items + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->delete('#__associations') + ->where('context=' . $db->quote('com_content.item')) + ->where('id IN (' . implode(',', $associations) . ')'); + $db->setQuery($query); + $db->execute(); + + if ($error = $db->getErrorMsg()) + { + $this->setError($error); + return false; + } + + if (!$all_language && count($associations)) + { + // Adding new association for these items + $key = md5(json_encode($associations)); + $query->clear() + ->insert('#__associations'); + + foreach ($associations as $id) + { + $query->values($id . ',' . $db->quote('com_content.item') . ',' . $db->quote($key)); + } + + $db->setQuery($query); + $db->execute(); + + if ($error = $db->getErrorMsg()) + { + $this->setError($error); + return false; + } + } + } + + return true; + } + + return false; + } + + /** + * Method to toggle the featured setting of articles. + * + * @param array The ids of the items to toggle. + * @param integer The value to toggle to. + * + * @return boolean True on success. + */ + public function featured($pks, $value = 0) + { + // Sanitize the ids. + $pks = (array) $pks; + JArrayHelper::toInteger($pks); + + if (empty($pks)) + { + $this->setError(JText::_('COM_CONTENT_NO_ITEM_SELECTED')); + return false; + } + + $table = $this->getTable('Featured', 'ContentTable'); + + try + { + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->update($db->quoteName('#__content')) + ->set('featured = ' . (int) $value) + ->where('id IN (' . implode(',', $pks) . ')'); + $db->setQuery($query); + $db->execute(); + + if ((int) $value == 0) + { + // Adjust the mapping table. + // Clear the existing features settings. + $query = $db->getQuery(true) + ->delete($db->quoteName('#__content_frontpage')) + ->where('content_id IN (' . implode(',', $pks) . ')'); + $db->setQuery($query); + $db->execute(); + } + else + { + // first, we find out which of our new featured articles are already featured. + $query = $db->getQuery(true) + ->select('f.content_id') + ->from('#__content_frontpage AS f') + ->where('content_id IN (' . implode(',', $pks) . ')'); + //echo $query; + $db->setQuery($query); + + $old_featured = $db->loadColumn(); + + // we diff the arrays to get a list of the articles that are newly featured + $new_featured = array_diff($pks, $old_featured); + + // Featuring. + $tuples = array(); + foreach ($new_featured as $pk) + { + $tuples[] = $pk . ', 0'; + } + if (count($tuples)) + { + $db = $this->getDbo(); + $columns = array('content_id', 'ordering'); + $query = $db->getQuery(true) + ->insert($db->quoteName('#__content_frontpage')) + ->columns($db->quoteName($columns)) + ->values($tuples); + $db->setQuery($query); + $db->execute(); + } + } + } + catch (Exception $e) + { + $this->setError($e->getMessage()); + return false; + } + + $table->reorder(); + + $this->cleanCache(); + + return true; + } + + /** + * A protected method to get a set of ordering conditions. + * + * @param object A record object. + * + * @return array An array of conditions to add to add to ordering queries. + * @since 1.6 + */ + protected function getReorderConditions($table) + { + $condition = array(); + $condition[] = 'catid = ' . (int) $table->catid; + return $condition; + } + + /** + * Auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @return void + * @since 3.0 + */ + protected function preprocessForm(JForm $form, $data, $group = 'content') + { + // Association content items + $app = JFactory::getApplication(); + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $languages = JLanguageHelper::getLanguages('lang_code'); + + // force to array (perhaps move to $this->loadFormData()) + $data = (array) $data; + + $addform = new SimpleXMLElement('
'); + $fields = $addform->addChild('fields'); + $fields->addAttribute('name', 'associations'); + $fieldset = $fields->addChild('fieldset'); + $fieldset->addAttribute('name', 'item_associations'); + $fieldset->addAttribute('description', 'COM_CONTENT_ITEM_ASSOCIATIONS_FIELDSET_DESC'); + $add = false; + foreach ($languages as $tag => $language) + { + if (empty($data['language']) || $tag != $data['language']) + { + $add = true; + $field = $fieldset->addChild('field'); + $field->addAttribute('name', $tag); + $field->addAttribute('type', 'modal_article'); + $field->addAttribute('language', $tag); + $field->addAttribute('label', $language->title); + $field->addAttribute('translate_label', 'false'); + $field->addAttribute('edit', 'true'); + $field->addAttribute('clear', 'true'); + } + } + if ($add) + { + $form->load($addform, false); + } + } + + parent::preprocessForm($form, $data, $group); + } + + /** + * Custom clean the cache of com_content and content modules + * + * @since 1.6 + */ + protected function cleanCache($group = null, $client_id = 0) + { + parent::cleanCache('com_content'); + parent::cleanCache('mod_articles_archive'); + parent::cleanCache('mod_articles_categories'); + parent::cleanCache('mod_articles_category'); + parent::cleanCache('mod_articles_latest'); + parent::cleanCache('mod_articles_news'); + parent::cleanCache('mod_articles_popular'); + } +} diff --git a/administrator/components/com_content/models/articles.php b/administrator/components/com_content/models/articles.php new file mode 100644 index 0000000..215ffb0 --- /dev/null +++ b/administrator/components/com_content/models/articles.php @@ -0,0 +1,372 @@ +item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $config['filter_fields'][] = 'association'; + } + } + + parent::__construct($config); + } + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @param string $ordering An optional ordering field. + * @param string $direction An optional direction (asc|desc). + * + * @return void + * + * @since 1.6 + */ + protected function populateState($ordering = null, $direction = null) + { + $app = JFactory::getApplication(); + + // Adjust the context to support modal layouts. + if ($layout = $app->input->get('layout')) + { + $this->context .= '.' . $layout; + } + + $search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $access = $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access', 0, 'int'); + $this->setState('filter.access', $access); + + $authorId = $app->getUserStateFromRequest($this->context . '.filter.author_id', 'filter_author_id'); + $this->setState('filter.author_id', $authorId); + + $published = $this->getUserStateFromRequest($this->context . '.filter.published', 'filter_published', ''); + $this->setState('filter.published', $published); + + $categoryId = $this->getUserStateFromRequest($this->context . '.filter.category_id', 'filter_category_id'); + $this->setState('filter.category_id', $categoryId); + + $level = $this->getUserStateFromRequest($this->context . '.filter.level', 'filter_level', 0, 'int'); + $this->setState('filter.level', $level); + + $language = $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', ''); + $this->setState('filter.language', $language); + + // force a language + $forcedLanguage = $app->input->get('forcedLanguage'); + if (!empty($forcedLanguage)) + { + $this->setState('filter.language', $forcedLanguage); + $this->setState('filter.forcedLanguage', $forcedLanguage); + } + + $tag = $this->getUserStateFromRequest($this->context . '.filter.tag', 'filter_tag', ''); + $this->setState('filter.tag', $tag); + + // List state information. + parent::populateState('a.title', 'asc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + * @since 1.6 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.access'); + $id .= ':' . $this->getState('filter.published'); + $id .= ':' . $this->getState('filter.category_id'); + $id .= ':' . $this->getState('filter.author_id'); + $id .= ':' . $this->getState('filter.language'); + + return parent::getStoreId($id); + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery + * @since 1.6 + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + $user = JFactory::getUser(); + $app = JFactory::getApplication(); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.id, a.title, a.alias, a.checked_out, a.checked_out_time, a.catid' . + ', a.state, a.access, a.created, a.created_by, a.created_by_alias, a.ordering, a.featured, a.language, a.hits' . + ', a.publish_up, a.publish_down' + ) + ); + $query->from('#__content AS a'); + + // Join over the language + $query->select('l.title AS language_title') + ->join('LEFT', $db->quoteName('#__languages') . ' AS l ON l.lang_code = a.language'); + + // Join over the users for the checked out user. + $query->select('uc.name AS editor') + ->join('LEFT', '#__users AS uc ON uc.id=a.checked_out'); + + // Join over the asset groups. + $query->select('ag.title AS access_level') + ->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access'); + + // Join over the categories. + $query->select('c.title AS category_title') + ->join('LEFT', '#__categories AS c ON c.id = a.catid'); + + // Join over the users for the author. + $query->select('ua.name AS author_name') + ->join('LEFT', '#__users AS ua ON ua.id = a.created_by'); + + // Join over the associations. + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $query->select('COUNT(asso2.id)>1 as association') + ->join('LEFT', '#__associations AS asso ON asso.id = a.id AND asso.context=' . $db->quote('com_content.item')) + ->join('LEFT', '#__associations AS asso2 ON asso2.key = asso.key') + ->group('a.id'); + } + + // Filter by access level. + if ($access = $this->getState('filter.access')) + { + $query->where('a.access = ' . (int) $access); + } + + // Implement View Level Access + if (!$user->authorise('core.admin')) + { + $groups = implode(',', $user->getAuthorisedViewLevels()); + $query->where('a.access IN (' . $groups . ')'); + } + + // Filter by published state + $published = $this->getState('filter.published'); + if (is_numeric($published)) + { + $query->where('a.state = ' . (int) $published); + } + elseif ($published === '') + { + $query->where('(a.state = 0 OR a.state = 1)'); + } + + // Filter by a single or group of categories. + $baselevel = 1; + $categoryId = $this->getState('filter.category_id'); + if (is_numeric($categoryId)) + { + $cat_tbl = JTable::getInstance('Category', 'JTable'); + $cat_tbl->load($categoryId); + $rgt = $cat_tbl->rgt; + $lft = $cat_tbl->lft; + $baselevel = (int) $cat_tbl->level; + $query->where('c.lft >= ' . (int) $lft) + ->where('c.rgt <= ' . (int) $rgt); + } + elseif (is_array($categoryId)) + { + JArrayHelper::toInteger($categoryId); + $categoryId = implode(',', $categoryId); + $query->where('a.catid IN (' . $categoryId . ')'); + } + + // Filter on the level. + if ($level = $this->getState('filter.level')) + { + $query->where('c.level <= ' . ((int) $level + (int) $baselevel - 1)); + } + + // Filter by author + $authorId = $this->getState('filter.author_id'); + if (is_numeric($authorId)) + { + $type = $this->getState('filter.author_id.include', true) ? '= ' : '<>'; + $query->where('a.created_by ' . $type . (int) $authorId); + } + + // Filter by search in title. + $search = $this->getState('filter.search'); + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + elseif (stripos($search, 'author:') === 0) + { + $search = $db->quote('%' . $db->escape(substr($search, 7), true) . '%'); + $query->where('(ua.name LIKE ' . $search . ' OR ua.username LIKE ' . $search . ')'); + } + else + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('(a.title LIKE ' . $search . ' OR a.alias LIKE ' . $search . ')'); + } + } + + // Filter on the language. + if ($language = $this->getState('filter.language')) + { + $query->where('a.language = ' . $db->quote($language)); + } + + // Filter by a single tag. + $tagId = $this->getState('filter.tag'); + if (is_numeric($tagId)) + { + $query->where($db->quoteName('tagmap.tag_id') . ' = ' . (int) $tagId) + ->join( + 'LEFT', $db->quoteName('#__contentitem_tag_map', 'tagmap') + . ' ON ' . $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id') + . ' AND ' . $db->quoteName('tagmap.type_alias') . ' = ' . $db->quote('com_content.article') + ); + } + + // Add the list ordering clause. + $orderCol = $this->state->get('list.ordering', 'a.title'); + $orderDirn = $this->state->get('list.direction', 'asc'); + if ($orderCol == 'a.ordering' || $orderCol == 'category_title') + { + $orderCol = 'c.title ' . $orderDirn . ', a.ordering'; + } + //sqlsrv change + if ($orderCol == 'language') + { + $orderCol = 'l.title'; + } + if ($orderCol == 'access_level') + { + $orderCol = 'ag.title'; + } + $query->order($db->escape($orderCol . ' ' . $orderDirn)); + + // echo nl2br(str_replace('#__','jos_',$query)); + return $query; + } + + /** + * Build a list of authors + * + * @return JDatabaseQuery + * @since 1.6 + */ + public function getAuthors() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Construct the query + $query->select('u.id AS value, u.name AS text') + ->from('#__users AS u') + ->join('INNER', '#__content AS c ON c.created_by = u.id') + ->group('u.id, u.name') + ->order('u.name'); + + // Setup the query + $db->setQuery($query); + + // Return the result + return $db->loadObjectList(); + } + + /** + * Method to get a list of articles. + * Overridden to add a check for access levels. + * + * @return mixed An array of data items on success, false on failure. + * @since 1.6.1 + */ + public function getItems() + { + $items = parent::getItems(); + $app = JFactory::getApplication(); + if ($app->isSite()) + { + $user = JFactory::getUser(); + $groups = $user->getAuthorisedViewLevels(); + + for ($x = 0, $count = count($items); $x < $count; $x++) + { + //Check the access level. Remove articles the user shouldn't see + if (!in_array($items[$x]->access, $groups)) + { + unset($items[$x]); + } + } + } + return $items; + } +} diff --git a/administrator/components/com_content/models/feature.php b/administrator/components/com_content/models/feature.php new file mode 100644 index 0000000..9681218 --- /dev/null +++ b/administrator/components/com_content/models/feature.php @@ -0,0 +1,47 @@ +getDbo(); + $query = $db->getQuery(true); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.id, a.title, a.alias, a.checked_out, a.checked_out_time, a.catid, a.state, a.access, a.created, a.hits,' . + 'a.language, a.created_by_alias, a.publish_up, a.publish_down' + ) + ); + $query->from('#__content AS a'); + + // Join over the language + $query->select('l.title AS language_title') + ->join('LEFT', $db->quoteName('#__languages') . ' AS l ON l.lang_code = a.language'); + + // Join over the content table. + $query->select('fp.ordering') + ->join('INNER', '#__content_frontpage AS fp ON fp.content_id = a.id'); + + // Join over the users for the checked out user. + $query->select('uc.name AS editor') + ->join('LEFT', '#__users AS uc ON uc.id=a.checked_out'); + + // Join over the asset groups. + $query->select('ag.title AS access_level') + ->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access'); + + // Join over the categories. + $query->select('c.title AS category_title') + ->join('LEFT', '#__categories AS c ON c.id = a.catid'); + + // Join over the users for the author. + $query->select('ua.name AS author_name') + ->join('LEFT', '#__users AS ua ON ua.id = a.created_by'); + + // Filter by access level. + if ($access = $this->getState('filter.access')) + { + $query->where('a.access = ' . (int) $access); + } + + // Filter by published state + $published = $this->getState('filter.published'); + if (is_numeric($published)) + { + $query->where('a.state = ' . (int) $published); + } + elseif ($published === '') + { + $query->where('(a.state = 0 OR a.state = 1)'); + } + + // Filter by a single or group of categories. + $baselevel = 1; + $categoryId = $this->getState('filter.category_id'); + if (is_numeric($categoryId)) + { + $cat_tbl = JTable::getInstance('Category', 'JTable'); + $cat_tbl->load($categoryId); + $rgt = $cat_tbl->rgt; + $lft = $cat_tbl->lft; + $baselevel = (int) $cat_tbl->level; + $query->where('c.lft >= ' . (int) $lft) + ->where('c.rgt <= ' . (int) $rgt); + } + elseif (is_array($categoryId)) + { + JArrayHelper::toInteger($categoryId); + $categoryId = implode(',', $categoryId); + $query->where('a.catid IN (' . $categoryId . ')'); + } + + // Filter on the level. + if ($level = $this->getState('filter.level')) + { + $query->where('c.level <= ' . ((int) $level + (int) $baselevel - 1)); + } + + // Filter by search in title + $search = $this->getState('filter.search'); + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + else + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('a.title LIKE ' . $search . ' OR a.alias LIKE ' . $search); + } + } + + // Filter on the language. + if ($language = $this->getState('filter.language')) + { + $query->where('a.language = ' . $db->quote($language)); + } + + // Add the list ordering clause. + $query->order($db->escape($this->getState('list.ordering', 'a.title')) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))); + + //echo nl2br(str_replace('#__','jos_',(string)$query)); + return $query; + } +} diff --git a/administrator/components/com_content/models/fields/index.html b/administrator/components/com_content/models/fields/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/models/fields/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/models/fields/modal/article.php b/administrator/components/com_content/models/fields/modal/article.php new file mode 100644 index 0000000..0e7107b --- /dev/null +++ b/administrator/components/com_content/models/fields/modal/article.php @@ -0,0 +1,159 @@ +element['edit'] == 'true') ? true : false; + $allowClear = ((string) $this->element['clear'] != 'false') ? true : false; + + // Load language + JFactory::getLanguage()->load('com_content', JPATH_ADMINISTRATOR); + + // Load the modal behavior script. + JHtml::_('behavior.modal', 'a.modal'); + + // Build the script. + $script = array(); + + // Select button script + $script[] = ' function jSelectArticle_'.$this->id.'(id, title, catid, object) {'; + $script[] = ' document.getElementById("'.$this->id.'_id").value = id;'; + $script[] = ' document.getElementById("'.$this->id.'_name").value = title;'; + + if ($allowEdit) + { + $script[] = ' jQuery("#'.$this->id.'_edit").removeClass("hidden");'; + } + + if ($allowClear) + { + $script[] = ' jQuery("#'.$this->id.'_clear").removeClass("hidden");'; + } + + $script[] = ' SqueezeBox.close();'; + $script[] = ' }'; + + // Clear button script + static $scriptClear; + + if ($allowClear && !$scriptClear) + { + $scriptClear = true; + + $script[] = ' function jClearArticle(id) {'; + $script[] = ' document.getElementById(id + "_id").value = "";'; + $script[] = ' document.getElementById(id + "_name").value = "'.htmlspecialchars(JText::_('COM_CONTENT_SELECT_AN_ARTICLE', true), ENT_COMPAT, 'UTF-8').'";'; + $script[] = ' jQuery("#"+id + "_clear").addClass("hidden");'; + $script[] = ' if (document.getElementById(id + "_edit")) {'; + $script[] = ' jQuery("#"+id + "_edit").addClass("hidden");'; + $script[] = ' }'; + $script[] = ' return false;'; + $script[] = ' }'; + } + + // Add the script to the document head. + JFactory::getDocument()->addScriptDeclaration(implode("\n", $script)); + + // Setup variables for display. + $html = array(); + $link = 'index.php?option=com_content&view=articles&layout=modal&tmpl=component&function=jSelectArticle_'.$this->id; + + if (isset($this->element['language'])) + { + $link .= '&forcedLanguage='.$this->element['language']; + } + + $db = JFactory::getDbo(); + $db->setQuery( + 'SELECT title' . + ' FROM #__content' . + ' WHERE id = '.(int) $this->value + ); + + try + { + $title = $db->loadResult(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + } + + if (empty($title)) + { + $title = JText::_('COM_CONTENT_SELECT_AN_ARTICLE'); + } + $title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); + + // The active article id field. + if (0 == (int) $this->value) + { + $value = ''; + } + else + { + $value = (int) $this->value; + } + + // The current article display field. + $html[] = ''; + $html[] = ''; + $html[] = ' '.JText::_('JSELECT').''; + + // Edit article button + if ($allowEdit) + { + $html[] = ' ' . JText::_('JACTION_EDIT') . ''; + } + + // Clear article button + if ($allowClear) + { + $html[] = ''; + } + + $html[] = ''; + + // class='required' for client side validation + $class = ''; + if ($this->required) + { + $class = ' class="required modal-value"'; + } + + $html[] = ''; + + return implode("\n", $html); + } +} diff --git a/administrator/components/com_content/models/fields/modal/index.html b/administrator/components/com_content/models/fields/modal/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/models/fields/modal/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/models/forms/article.xml b/administrator/components/com_content/models/forms/article.xml new file mode 100644 index 0000000..80412e5 --- /dev/null +++ b/administrator/components/com_content/models/forms/article.xml @@ -0,0 +1,838 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+
+ + diff --git a/administrator/components/com_content/models/forms/index.html b/administrator/components/com_content/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/models/index.html b/administrator/components/com_content/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/tables/featured.php b/administrator/components/com_content/tables/featured.php new file mode 100644 index 0000000..d24da04 --- /dev/null +++ b/administrator/components/com_content/tables/featured.php @@ -0,0 +1,25 @@ + diff --git a/administrator/components/com_content/views/article/index.html b/administrator/components/com_content/views/article/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/views/article/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/views/article/tmpl/edit.php b/administrator/components/com_content/views/article/tmpl/edit.php new file mode 100644 index 0000000..c1c0b14 --- /dev/null +++ b/administrator/components/com_content/views/article/tmpl/edit.php @@ -0,0 +1,297 @@ +state->get('params'); +$params = $params->toArray(); + +// This checks if the config options have ever been saved. If they haven't they will fall back to the original settings. +$editoroptions = isset($params['show_publishing_options']); + +$app = JFactory::getApplication(); +$input = $app->input; + +$assoc = isset($app->item_associations) ? $app->item_associations : 0; + +if (!$editoroptions) +{ + $params['show_publishing_options'] = '1'; + $params['show_article_options'] = '1'; + $params['show_urls_images_backend'] = '0'; + $params['show_urls_images_frontend'] = '0'; +} + +// Check if the article uses configuration settings besides global. If so, use them. +if (!empty($this->item->attribs['show_publishing_options'])) +{ + $params['show_publishing_options'] = $this->item->attribs['show_publishing_options']; +} + +if (!empty($this->item->attribs['show_article_options'])) +{ + $params['show_article_options'] = $this->item->attribs['show_article_options']; +} + +if (!empty($this->item->attribs['show_urls_images_backend'])) +{ + $params['show_urls_images_backend'] = $this->item->attribs['show_urls_images_backend']; +} + +?> + + + +
+ + + +
+ +
+ 'general')); ?> + + +
+
+ form->getLabel('title'); ?> form->getInput('title'); ?> form->getLabel('catid'); ?> form->getInput('catid'); ?> +
+ form->getInput('articletext'); ?> +
+ + +
+
+

+
+ form->getLabel('images'); ?> +
+ form->getInput('images'); ?> +
+
+ form->getGroup('images') as $field) : ?> +
+ hidden) : ?> + label; ?> + +
+ input; ?> +
+
+ +
+
+ form->getGroup('urls') as $field) : ?> +
+ hidden) : ?> + label; ?> + +
+ input; ?> +
+
+ +
+
+ + + + + + +
+
+
+ form->getLabel('alias'); ?> +
+ form->getInput('alias'); ?> +
+
+
+
+ form->getLabel('id'); ?> +
+
+ form->getInput('id'); ?> +
+
+
+ form->getLabel('created_by'); ?> +
+ form->getInput('created_by'); ?> +
+
+
+ form->getLabel('created_by_alias'); ?> +
+ form->getInput('created_by_alias'); ?> +
+
+
+ form->getLabel('created'); ?> +
+ form->getInput('created'); ?> +
+
+
+
+
+ form->getLabel('publish_up'); ?> +
+ form->getInput('publish_up'); ?> +
+
+
+ form->getLabel('publish_down'); ?> +
+ form->getInput('publish_down'); ?> +
+
+ item->modified_by) : ?> +
+ form->getLabel('modified_by'); ?> +
+ form->getInput('modified_by'); ?> +
+
+
+ form->getLabel('modified'); ?> +
+ form->getInput('modified'); ?> +
+
+ + + item->version) : ?> +
+ form->getLabel('version'); ?> +
+ form->getInput('version'); ?> +
+
+ + + item->hits) : ?> +
+
+ form->getLabel('hits'); ?> +
+
+ form->getInput('hits'); ?> +
+
+ +
+
+ + + + + form->getFieldsets('attribs'); ?> + $fieldSet) : ?> + + + label, true)); ?> + + + + + + + description) && trim($fieldSet->description)) : ?> +

escape(JText::_($fieldSet->description));?>

+ + form->getFieldset($name) as $field) : ?> +
+ label; ?> +
+ input; ?> +
+
+ + + + form->getFieldset('basic-limited') as $field) : + echo $field->input; + endforeach; + endif;?> + + + + + + + + + + canDo->get('core.admin')): ?> + + form->getFieldset('editorConfig') as $field) : ?> +
+ label; ?> +
+ input; ?> +
+
+ + + + + + loadTemplate('metadata'); ?> + + + + + loadTemplate('associations'); ?> + + + + canDo->get('core.admin')) : ?> + +
+ form->getInput('rules'); ?> +
+ + + + + + + + +
+ + + + +
+
diff --git a/administrator/components/com_content/views/article/tmpl/edit_associations.php b/administrator/components/com_content/views/article/tmpl/edit_associations.php new file mode 100644 index 0000000..b0dcd5b --- /dev/null +++ b/administrator/components/com_content/views/article/tmpl/edit_associations.php @@ -0,0 +1,12 @@ + diff --git a/administrator/components/com_content/views/article/tmpl/index.html b/administrator/components/com_content/views/article/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/views/article/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/views/article/tmpl/modal.php b/administrator/components/com_content/views/article/tmpl/modal.php new file mode 100644 index 0000000..7d7685e --- /dev/null +++ b/administrator/components/com_content/views/article/tmpl/modal.php @@ -0,0 +1,312 @@ +state->get('params'); +$params = $params->toArray(); + +// This checks if the config options have ever been saved. If they haven't they will fall back to the original settings. +$editoroptions = isset($params['show_publishing_options']); + +$app = JFactory::getApplication(); +$input = $app->input; + +$assoc = isset($app->item_associations) ? $app->item_associations : 0; + +if (!$editoroptions) +{ + $params['show_publishing_options'] = '1'; + $params['show_article_options'] = '1'; + $params['show_urls_images_backend'] = '0'; + $params['show_urls_images_frontend'] = '0'; +} + +// Check if the article uses configuration settings besides global. If so, use them. +if (!empty($this->item->attribs['show_publishing_options'])) +{ + $params['show_publishing_options'] = $this->item->attribs['show_publishing_options']; +} + +if (!empty($this->item->attribs['show_article_options'])) +{ + $params['show_article_options'] = $this->item->attribs['show_article_options']; +} + +if (!empty($this->item->attribs['show_urls_images_backend'])) +{ + $params['show_urls_images_backend'] = $this->item->attribs['show_urls_images_backend']; +} + +?> + + +
+ +
+ + + +
+ +
+
+ +
+
+ +
+ 'general')); ?> + + +
+
+ form->getLabel('title'); ?> form->getInput('title'); ?> form->getLabel('catid'); ?> form->getInput('catid'); ?> +
+ form->getInput('articletext'); ?> +
+ + +
+
+

+
+ form->getLabel('images'); ?> +
+ form->getInput('images'); ?> +
+
+ form->getGroup('images') as $field) : ?> +
+ hidden) : ?> + label; ?> + +
+ input; ?> +
+
+ +
+
+ form->getGroup('urls') as $field) : ?> +
+ hidden) : ?> + label; ?> + +
+ input; ?> +
+
+ +
+
+ + + + + + +
+
+
+ form->getLabel('alias'); ?> +
+ form->getInput('alias'); ?> +
+
+
+
+ form->getLabel('id'); ?> +
+
+ form->getInput('id'); ?> +
+
+
+ form->getLabel('created_by'); ?> +
+ form->getInput('created_by'); ?> +
+
+
+ form->getLabel('created_by_alias'); ?> +
+ form->getInput('created_by_alias'); ?> +
+
+
+ form->getLabel('created'); ?> +
+ form->getInput('created'); ?> +
+
+
+
+
+ form->getLabel('publish_up'); ?> +
+ form->getInput('publish_up'); ?> +
+
+
+ form->getLabel('publish_down'); ?> +
+ form->getInput('publish_down'); ?> +
+
+ item->modified_by) : ?> +
+ form->getLabel('modified_by'); ?> +
+ form->getInput('modified_by'); ?> +
+
+
+ form->getLabel('modified'); ?> +
+ form->getInput('modified'); ?> +
+
+ + + item->version) : ?> +
+ form->getLabel('version'); ?> +
+ form->getInput('version'); ?> +
+
+ + + item->hits) : ?> +
+
+ form->getLabel('hits'); ?> +
+
+ form->getInput('hits'); ?> +
+
+ +
+
+ + + + + form->getFieldsets('attribs'); ?> + $fieldSet) : ?> + + + label, true)); ?> + + + + + + + description) && trim($fieldSet->description)) : ?> +

escape(JText::_($fieldSet->description));?>

+ + form->getFieldset($name) as $field) : ?> +
+ label; ?> +
+ input; ?> +
+
+ + + + form->getFieldset('basic-limited') as $field) : + echo $field->input; + endforeach; + endif;?> + + + + + + + + + + canDo->get('core.admin')): ?> + + form->getFieldset('editorConfig') as $field) : ?> +
+ label; ?> +
+ input; ?> +
+
+ + + + + + loadTemplate('metadata'); ?> + + + canDo->get('core.admin')) : ?> + +
+ form->getInput('rules'); ?> +
+ + + + + + + + + + +
+ + + + +
+
+
\ No newline at end of file diff --git a/administrator/components/com_content/views/article/tmpl/modal_associations.php b/administrator/components/com_content/views/article/tmpl/modal_associations.php new file mode 100644 index 0000000..b0dcd5b --- /dev/null +++ b/administrator/components/com_content/views/article/tmpl/modal_associations.php @@ -0,0 +1,12 @@ + diff --git a/administrator/components/com_content/views/article/tmpl/pagebreak.php b/administrator/components/com_content/views/article/tmpl/pagebreak.php new file mode 100644 index 0000000..805f59d --- /dev/null +++ b/administrator/components/com_content/views/article/tmpl/pagebreak.php @@ -0,0 +1,56 @@ +";'."\n\t"; +$script .= 'window.parent.jInsertEditorText(tag, \''.$this->eName.'\');'."\n\t"; +$script .= 'window.parent.SqueezeBox.close();'."\n\t"; +$script .= 'return false;'."\n"; +$script .= '}'."\n"; + +JFactory::getDocument()->addScriptDeclaration($script); +?> +
+ + + + + + + + + +
+ + + +
+ + + +
+
+ diff --git a/administrator/components/com_content/views/article/view.html.php b/administrator/components/com_content/views/article/view.html.php new file mode 100644 index 0000000..1a1e8f3 --- /dev/null +++ b/administrator/components/com_content/views/article/view.html.php @@ -0,0 +1,122 @@ +getLayout() == 'pagebreak') + { + // TODO: This is really dogy - should change this one day. + $eName = JRequest::getVar('e_name'); + $eName = preg_replace('#[^A-Z0-9\-\_\[\]]#i', '', $eName); + $document = JFactory::getDocument(); + $document->setTitle(JText::_('COM_CONTENT_PAGEBREAK_DOC_TITLE')); + $this->eName = &$eName; + parent::display($tpl); + return; + } + + $this->form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + $this->canDo = ContentHelper::getActions($this->state->get('filter.category_id')); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + if ($this->getLayout() == 'modal') + { + $this->form->setFieldAttribute('language', 'readonly', 'true'); + $this->form->setFieldAttribute('catid', 'readonly', 'true'); + } + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + JFactory::getApplication()->input->set('hidemainmenu', true); + $user = JFactory::getUser(); + $userId = $user->get('id'); + $isNew = ($this->item->id == 0); + $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $userId); + $canDo = ContentHelper::getActions($this->state->get('filter.category_id'), $this->item->id); + JToolbarHelper::title(JText::_('COM_CONTENT_PAGE_'.($checkedOut ? 'VIEW_ARTICLE' : ($isNew ? 'ADD_ARTICLE' : 'EDIT_ARTICLE'))), 'article-add.png'); + + // Built the actions for new and existing records. + + // For new records, check the create permission. + if ($isNew && (count($user->getAuthorisedCategories('com_content', 'core.create')) > 0)) + { + JToolbarHelper::apply('article.apply'); + JToolbarHelper::save('article.save'); + JToolbarHelper::save2new('article.save2new'); + JToolbarHelper::cancel('article.cancel'); + } + else + { + // Can't save the record if it's checked out. + if (!$checkedOut) + { + // Since it's an existing record, check the edit permission, or fall back to edit own if the owner. + if ($canDo->get('core.edit') || ($canDo->get('core.edit.own') && $this->item->created_by == $userId)) + { + JToolbarHelper::apply('article.apply'); + JToolbarHelper::save('article.save'); + + // We can save this record, but check the create permission to see if we can return to make a new one. + if ($canDo->get('core.create')) + { + JToolbarHelper::save2new('article.save2new'); + } + } + } + + // If checked out, we can still save + if ($canDo->get('core.create')) + { + JToolbarHelper::save2copy('article.save2copy'); + } + + JToolbarHelper::cancel('article.cancel', 'JTOOLBAR_CLOSE'); + } + + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_CONTENT_ARTICLE_MANAGER_EDIT'); + } +} diff --git a/administrator/components/com_content/views/articles/index.html b/administrator/components/com_content/views/articles/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/views/articles/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/views/articles/tmpl/default.php b/administrator/components/com_content/views/articles/tmpl/default.php new file mode 100644 index 0000000..b836138 --- /dev/null +++ b/administrator/components/com_content/views/articles/tmpl/default.php @@ -0,0 +1,283 @@ +get('id'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$archived = $this->state->get('filter.published') == 2 ? true : false; +$trashed = $this->state->get('filter.published') == -2 ? true : false; +$saveOrder = $listOrder == 'a.ordering'; +if ($saveOrder) +{ + $saveOrderingUrl = 'index.php?option=com_content&task=articles.saveOrderAjax&tmpl=component'; + JHtml::_('sortablelist.sortable', 'articleList', 'adminForm', strtolower($listDirn), $saveOrderingUrl); +} + +$sortFields = $this->getSortFields(); +$assoc = isset($app->item_associations) ? $app->item_associations : 0; +?> + + +
+sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ +
+ +
+ + +
+
+ + pagination->getLimitBox(); ?> +
+
+ + +
+
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + + + items as $i => $item) : + $item->max_ordering = 0; //?? + $ordering = ($listOrder == 'a.ordering'); + $canCreate = $user->authorise('core.create', 'com_content.category.'.$item->catid); + $canEdit = $user->authorise('core.edit', 'com_content.article.'.$item->id); + $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $userId || $item->checked_out == 0; + $canEditOwn = $user->authorise('core.edit.own', 'com_content.article.'.$item->id) && $item->created_by == $userId; + $canChange = $user->authorise('core.edit.state', 'com_content.article.'.$item->id) && $canCheckin; + ?> + + + + + + + + + + + + + + + + + +
+ ', 'a.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING'); ?> + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + id); ?> + +
+ state, $i, 'articles.', $canChange, 'cb', $item->publish_up, $item->publish_down); ?> + featured, $i, $canChange); ?> +
+
+
+ checked_out) : ?> + editor, $item->checked_out_time, 'articles.', $canCheckin); ?> + + language == '*'):?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + + escape($item->title); ?> + + escape($item->title); ?> + +
+ escape($item->category_title); ?> +
+
+
+ id, 'article.'); + JHtml::_('dropdown.divider'); + if ($item->state) : + JHtml::_('dropdown.unpublish', 'cb' . $i, 'articles.'); + else : + JHtml::_('dropdown.publish', 'cb' . $i, 'articles.'); + endif; + + if ($item->featured) : + JHtml::_('dropdown.unfeatured', 'cb' . $i, 'articles.'); + else : + JHtml::_('dropdown.featured', 'cb' . $i, 'articles.'); + endif; + + JHtml::_('dropdown.divider'); + + if ($archived) : + JHtml::_('dropdown.unarchive', 'cb' . $i, 'articles.'); + else : + JHtml::_('dropdown.archive', 'cb' . $i, 'articles.'); + endif; + + if ($item->checked_out) : + JHtml::_('dropdown.checkin', 'cb' . $i, 'articles.'); + endif; + + if ($trashed) : + JHtml::_('dropdown.untrash', 'cb' . $i, 'articles.'); + else : + JHtml::_('dropdown.trash', 'cb' . $i, 'articles.'); + endif; + + // Render dropdown list + echo JHtml::_('dropdown.render'); + ?> +
+
+ escape($item->access_level); ?> + + association) : ?> + id); ?> + + + created_by_alias) : ?> + + escape($item->author_name); ?> +

escape($item->created_by_alias)); ?>

+ + + escape($item->author_name); ?> + +
+ language == '*'):?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + created, JText::_('DATE_FORMAT_LC4')); ?> + + hits; ?> + + id; ?> +
+ pagination->getListFooter(); ?> + + loadTemplate('batch'); ?> + + + + + + +
+ diff --git a/administrator/components/com_content/views/articles/tmpl/default_batch.php b/administrator/components/com_content/views/articles/tmpl/default_batch.php new file mode 100644 index 0000000..21ed1ec --- /dev/null +++ b/administrator/components/com_content/views/articles/tmpl/default_batch.php @@ -0,0 +1,52 @@ +state->get('filter.published'); +?> + diff --git a/administrator/components/com_content/views/articles/tmpl/index.html b/administrator/components/com_content/views/articles/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/views/articles/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/views/articles/tmpl/modal.php b/administrator/components/com_content/views/articles/tmpl/modal.php new file mode 100644 index 0000000..1b079b4 --- /dev/null +++ b/administrator/components/com_content/views/articles/tmpl/modal.php @@ -0,0 +1,167 @@ +isSite()) +{ + JSession::checkToken('get') or die(JText::_('JINVALID_TOKEN')); +} + +require_once JPATH_ROOT . '/components/com_content/helpers/route.php'; + +JHtml::addIncludePath(JPATH_COMPONENT.'/helpers/html'); +JHtml::_('bootstrap.tooltip'); + +$function = $app->input->getCmd('function', 'jSelectArticle'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +?> +
+
+
+
+ +
+
+ +
+
+ + +
+
+
+
+
+ + + + + state->get('filter.forcedLanguage')) : ?> + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + items as $i => $item) : ?> + language && JLanguageMultilang::isEnabled()) + { + $tag = strlen($item->language); + if ($tag == 5) + { + $lang = substr($item->language, 0, 2); + } + elseif ($tag == 6) + { + $lang = substr($item->language, 0, 3); + } + else { + $lang = ""; + } + } + elseif (!JLanguageMultilang::isEnabled()) + { + $lang = ""; + } + ?> + + + + + + + + + + +
+ + + + + + + + + + + +
+ pagination->getListFooter(); ?> +
+ + escape($item->title); ?> + + escape($item->access_level); ?> + + escape($item->category_title); ?> + + language == '*'):?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + created, JText::_('DATE_FORMAT_LC4')); ?> + + id; ?> +
+ +
+ + + + + +
+
diff --git a/administrator/components/com_content/views/articles/view.html.php b/administrator/components/com_content/views/articles/view.html.php new file mode 100644 index 0000000..2b5348d --- /dev/null +++ b/administrator/components/com_content/views/articles/view.html.php @@ -0,0 +1,206 @@ +getLayout() !== 'modal') + { + ContentHelper::addSubmenu('articles'); + } + + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + $this->authors = $this->get('Authors'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + // Levels filter. + $options = array(); + $options[] = JHtml::_('select.option', '1', JText::_('J1')); + $options[] = JHtml::_('select.option', '2', JText::_('J2')); + $options[] = JHtml::_('select.option', '3', JText::_('J3')); + $options[] = JHtml::_('select.option', '4', JText::_('J4')); + $options[] = JHtml::_('select.option', '5', JText::_('J5')); + $options[] = JHtml::_('select.option', '6', JText::_('J6')); + $options[] = JHtml::_('select.option', '7', JText::_('J7')); + $options[] = JHtml::_('select.option', '8', JText::_('J8')); + $options[] = JHtml::_('select.option', '9', JText::_('J9')); + $options[] = JHtml::_('select.option', '10', JText::_('J10')); + + $this->f_levels = $options; + + // We don't need toolbar in the modal window. + if ($this->getLayout() !== 'modal') + { + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + } + + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + $canDo = ContentHelper::getActions($this->state->get('filter.category_id')); + $user = JFactory::getUser(); + + // Get the toolbar object instance + $bar = JToolBar::getInstance('toolbar'); + + JToolbarHelper::title(JText::_('COM_CONTENT_ARTICLES_TITLE'), 'article.png'); + + if ($canDo->get('core.create') || (count($user->getAuthorisedCategories('com_content', 'core.create'))) > 0 ) + { + JToolbarHelper::addNew('article.add'); + } + + if (($canDo->get('core.edit')) || ($canDo->get('core.edit.own'))) + { + JToolbarHelper::editList('article.edit'); + } + + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::publish('articles.publish', 'JTOOLBAR_PUBLISH', true); + JToolbarHelper::unpublish('articles.unpublish', 'JTOOLBAR_UNPUBLISH', true); + JToolbarHelper::custom('articles.featured', 'featured.png', 'featured_f2.png', 'JFEATURED', true); + JToolbarHelper::archiveList('articles.archive'); + JToolbarHelper::checkin('articles.checkin'); + } + + if ($this->state->get('filter.published') == -2 && $canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'articles.delete', 'JTOOLBAR_EMPTY_TRASH'); + } + elseif ($canDo->get('core.edit.state')) + { + JToolbarHelper::trash('articles.trash'); + } + + // Add a batch button + if ($user->authorise('core.create', 'com_content') && $user->authorise('core.edit', 'com_content') && $user->authorise('core.edit.state', 'com_content')) + { + JHtml::_('bootstrap.modal', 'collapseModal'); + $title = JText::_('JTOOLBAR_BATCH'); + + // Instantiate a new JLayoutFile instance and render the batch button + $layout = new JLayoutFile('joomla.toolbar.batch'); + + $dhtml = $layout->render(array('title' => $title)); + $bar->appendButton('Custom', $dhtml, 'batch'); + } + + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_content'); + } + + JToolbarHelper::help('JHELP_CONTENT_ARTICLE_MANAGER'); + + JHtmlSidebar::setAction('index.php?option=com_content&view=articles'); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_published', + JHtml::_('select.options', JHtml::_('jgrid.publishedOptions'), 'value', 'text', $this->state->get('filter.published'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_CATEGORY'), + 'filter_category_id', + JHtml::_('select.options', JHtml::_('category.options', 'com_content'), 'value', 'text', $this->state->get('filter.category_id')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_MAX_LEVELS'), + 'filter_level', + JHtml::_('select.options', $this->f_levels, 'value', 'text', $this->state->get('filter.level')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_ACCESS'), + 'filter_access', + JHtml::_('select.options', JHtml::_('access.assetgroups'), 'value', 'text', $this->state->get('filter.access')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_AUTHOR'), + 'filter_author_id', + JHtml::_('select.options', $this->authors, 'value', 'text', $this->state->get('filter.author_id')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_LANGUAGE'), + 'filter_language', + JHtml::_('select.options', JHtml::_('contentlanguage.existing', true, true), 'value', 'text', $this->state->get('filter.language')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_TAG'), + 'filter_tag', + JHtml::_('select.options', JHtml::_('tag.options', true, true), 'value', 'text', $this->state->get('filter.tag')) + ); + } + + /** + * Returns an array of fields the table can be sorted by + * + * @return array Array containing the field name to sort by as the key and display text as value + * + * @since 3.0 + */ + protected function getSortFields() + { + return array( + 'a.ordering' => JText::_('JGRID_HEADING_ORDERING'), + 'a.state' => JText::_('JSTATUS'), + 'a.title' => JText::_('JGLOBAL_TITLE'), + 'category_title' => JText::_('JCATEGORY'), + 'access_level' => JText::_('JGRID_HEADING_ACCESS'), + 'a.created_by' => JText::_('JAUTHOR'), + 'language' => JText::_('JGRID_HEADING_LANGUAGE'), + 'a.created' => JText::_('JDATE'), + 'a.id' => JText::_('JGRID_HEADING_ID'), + 'a.featured' => JText::_('JFEATURED') + ); + } +} diff --git a/administrator/components/com_content/views/featured/index.html b/administrator/components/com_content/views/featured/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/views/featured/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/views/featured/tmpl/default.php b/administrator/components/com_content/views/featured/tmpl/default.php new file mode 100644 index 0000000..e2857c2 --- /dev/null +++ b/administrator/components/com_content/views/featured/tmpl/default.php @@ -0,0 +1,223 @@ +get('id'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$canOrder = $user->authorise('core.edit.state', 'com_content.article'); +$archived = $this->state->get('filter.published') == 2 ? true : false; +$trashed = $this->state->get('filter.published') == -2 ? true : false; +$saveOrder = $listOrder == 'fp.ordering'; +?> + +
+sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ +
+ +
+ + +
+
+ + pagination->getLimitBox(); ?> +
+
+
+ + + + + + + + + + + + + + + + + + + + + + items); ?> + items as $i => $item) : + $item->max_ordering = 0; + $ordering = ($listOrder == 'fp.ordering'); + $assetId = 'com_content.article.'.$item->id; + $canCreate = $user->authorise('core.create', 'com_content.category.'.$item->catid); + $canEdit = $user->authorise('core.edit', 'com_content.article.'.$item->id); + $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $userId || $item->checked_out == 0; + $canChange = $user->authorise('core.edit.state', 'com_content.article.'.$item->id) && $canCheckin; + ?> + + + + + + + + + + + + + +
+ + + + + + + + + items, 'filesave.png', 'featured.saveorder'); ?> + + + + + + + + + + + +
+ pagination->getListFooter(); ?> +
+ id); ?> + + state, $i, 'articles.', $canChange, 'cb', $item->publish_up, $item->publish_down); ?> + +
+ checked_out) : ?> + editor, $item->checked_out_time, 'articles.', $canCheckin); ?> + + language == '*') : ?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + + escape($item->title); ?> + + escape($item->title); ?> + +
+ escape($item->category_title); ?> +
+
+
+ id, 'article.', 'index.php?option=com_content&return=featured'); + JHtml::_('dropdown.divider'); + if ($item->state) : + JHtml::_('dropdown.unpublish', 'cb' . $i, 'articles.'); + else : + JHtml::_('dropdown.publish', 'cb' . $i, 'articles.'); + endif; + + JHtml::_('dropdown.divider'); + + if ($archived) : + JHtml::_('dropdown.unarchive', 'cb' . $i, 'articles.'); + else : + JHtml::_('dropdown.archive', 'cb' . $i, 'articles.'); + endif; + + if ($item->checked_out) : + JHtml::_('dropdown.checkin', 'cb' . $i, 'articles.'); + endif; + + if ($trashed) : + JHtml::_('dropdown.untrash', 'cb' . $i, 'articles.'); + else : + JHtml::_('dropdown.trash', 'cb' . $i, 'articles.'); + endif; + + // Render dropdown list + echo JHtml::_('dropdown.render'); + ?> +
+
+ +
+ + + pagination->orderUpIcon($i, true, 'featured.orderup', 'JLIB_HTML_MOVE_UP', $ordering); ?> + pagination->orderDownIcon($i, $count, true, 'featured.orderdown', 'JLIB_HTML_MOVE_DOWN', $ordering); ?> + + pagination->orderUpIcon($i, true, 'featured.orderdown', 'JLIB_HTML_MOVE_UP', $ordering); ?> + pagination->orderDownIcon($i, $count, true, 'featured.orderup', 'JLIB_HTML_MOVE_DOWN', $ordering); ?> + + + + class="width-20 text-area-order" /> +
+ + ordering; ?> + +
+ escape($item->access_level); ?> + + created_by_alias) : ?> + escape($item->author_name); ?> +

escape($item->created_by_alias)); ?>

+ + escape($item->author_name); ?> + +
+ language == '*'):?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + created, JText::_('DATE_FORMAT_LC4')); ?> + + id; ?> +
+ + + + + + + +
+ diff --git a/administrator/components/com_content/views/featured/tmpl/index.html b/administrator/components/com_content/views/featured/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/views/featured/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_content/views/featured/view.html.php b/administrator/components/com_content/views/featured/view.html.php new file mode 100644 index 0000000..70414c0 --- /dev/null +++ b/administrator/components/com_content/views/featured/view.html.php @@ -0,0 +1,167 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + $this->authors = $this->get('Authors'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + // Levels filter. + $options = array(); + $options[] = JHtml::_('select.option', '1', JText::_('J1')); + $options[] = JHtml::_('select.option', '2', JText::_('J2')); + $options[] = JHtml::_('select.option', '3', JText::_('J3')); + $options[] = JHtml::_('select.option', '4', JText::_('J4')); + $options[] = JHtml::_('select.option', '5', JText::_('J5')); + $options[] = JHtml::_('select.option', '6', JText::_('J6')); + $options[] = JHtml::_('select.option', '7', JText::_('J7')); + $options[] = JHtml::_('select.option', '8', JText::_('J8')); + $options[] = JHtml::_('select.option', '9', JText::_('J9')); + $options[] = JHtml::_('select.option', '10', JText::_('J10')); + + $this->f_levels = $options; + + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + $state = $this->get('State'); + $canDo = ContentHelper::getActions($this->state->get('filter.category_id')); + + JToolbarHelper::title(JText::_('COM_CONTENT_FEATURED_TITLE'), 'featured.png'); + + if ($canDo->get('core.create')) + { + JToolbarHelper::addNew('article.add'); + } + if ($canDo->get('core.edit')) + { + JToolbarHelper::editList('article.edit'); + } + + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::publish('articles.publish', 'JTOOLBAR_PUBLISH', true); + JToolbarHelper::unpublish('articles.unpublish', 'JTOOLBAR_UNPUBLISH', true); + JToolbarHelper::custom('featured.delete', 'remove.png', 'remove_f2.png', 'JTOOLBAR_REMOVE', true); + JToolbarHelper::archiveList('articles.archive'); + JToolbarHelper::checkin('articles.checkin'); + } + + if ($state->get('filter.published') == -2 && $canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'articles.delete', 'JTOOLBAR_EMPTY_TRASH'); + } elseif ($canDo->get('core.edit.state')) + { + JToolbarHelper::trash('articles.trash'); + } + + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_content'); + } + JToolbarHelper::help('JHELP_CONTENT_FEATURED_ARTICLES'); + + JHtmlSidebar::setAction('index.php?option=com_content&view=featured'); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_published', + JHtml::_('select.options', JHtml::_('jgrid.publishedOptions'), 'value', 'text', $this->state->get('filter.published'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_CATEGORY'), + 'filter_category_id', + JHtml::_('select.options', JHtml::_('category.options', 'com_content'), 'value', 'text', $this->state->get('filter.category_id')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_MAX_LEVELS'), + 'filter_level', + JHtml::_('select.options', $this->f_levels, 'value', 'text', $this->state->get('filter.level')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_ACCESS'), + 'filter_access', + JHtml::_('select.options', JHtml::_('access.assetgroups'), 'value', 'text', $this->state->get('filter.access')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_AUTHOR'), + 'filter_author_id', + JHtml::_('select.options', $this->authors, 'value', 'text', $this->state->get('filter.author_id')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_LANGUAGE'), + 'filter_language', + JHtml::_('select.options', JHtml::_('contentlanguage.existing', true, true), 'value', 'text', $this->state->get('filter.language')) + ); + } + + /** + * Returns an array of fields the table can be sorted by + * + * @return array Array containing the field name to sort by as the key and display text as value + * + * @since 3.0 + */ + protected function getSortFields() + { + return array( + 'fp.ordering' => JText::_('JGRID_HEADING_ORDERING'), + 'a.state' => JText::_('JSTATUS'), + 'a.title' => JText::_('JGLOBAL_TITLE'), + 'category_title' => JText::_('JCATEGORY'), + 'access_level' => JText::_('JGRID_HEADING_ACCESS'), + 'a.created_by' => JText::_('JAUTHOR'), + 'language' => JText::_('JGRID_HEADING_LANGUAGE'), + 'a.created' => JText::_('JDATE'), + 'a.id' => JText::_('JGRID_HEADING_ID') + ); + } +} diff --git a/administrator/components/com_content/views/index.html b/administrator/components/com_content/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_content/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_cpanel/controller.php b/administrator/components/com_cpanel/controller.php new file mode 100644 index 0000000..2894762 --- /dev/null +++ b/administrator/components/com_cpanel/controller.php @@ -0,0 +1,21 @@ +execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_cpanel/cpanel.xml b/administrator/components/com_cpanel/cpanel.xml new file mode 100644 index 0000000..a8cffd5 --- /dev/null +++ b/administrator/components/com_cpanel/cpanel.xml @@ -0,0 +1,25 @@ + + + com_cpanel + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_CPANEL_XML_DESCRIPTION + + + controller.php + cpanel.php + index.html + views + + + language/en-GB.com_cpanel.ini + language/en-GB.com_cpanel.sys.ini + + + + diff --git a/administrator/components/com_cpanel/index.html b/administrator/components/com_cpanel/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_cpanel/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_cpanel/views/cpanel/index.html b/administrator/components/com_cpanel/views/cpanel/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_cpanel/views/cpanel/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_cpanel/views/cpanel/tmpl/default.php b/administrator/components/com_cpanel/views/cpanel/tmpl/default.php new file mode 100644 index 0000000..b18855f --- /dev/null +++ b/administrator/components/com_cpanel/views/cpanel/tmpl/default.php @@ -0,0 +1,61 @@ + +
+
+ +
+
+ modules as $module) + { + $output = JModuleHelper::renderModule($module, array('style' => 'well')); + $params = new JRegistry; + $params->loadString($module->params); + echo $output; + } + ?> +
+
+ iconmodules = JModuleHelper::getModules('icon'); + foreach ($this->iconmodules as $iconmodule) + { + $output = JModuleHelper::renderModule($iconmodule, array('style' => 'well')); + $params = new JRegistry; + $params->loadString($iconmodule->params); + echo $output; + } + ?> +
+
diff --git a/administrator/components/com_cpanel/views/cpanel/tmpl/index.html b/administrator/components/com_cpanel/views/cpanel/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_cpanel/views/cpanel/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_cpanel/views/cpanel/view.html.php b/administrator/components/com_cpanel/views/cpanel/view.html.php new file mode 100644 index 0000000..1fa567d --- /dev/null +++ b/administrator/components/com_cpanel/views/cpanel/view.html.php @@ -0,0 +1,42 @@ +input; + + /* + * Set the template - this will display cpanel.php + * from the selected admin template. + */ + $input->set('tmpl', 'cpanel'); + + // Display the cpanel modules + $this->modules = JModuleHelper::getModules('cpanel'); + + parent::display($tpl); + } +} diff --git a/administrator/components/com_cpanel/views/index.html b/administrator/components/com_cpanel/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_cpanel/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_finder/access.xml b/administrator/components/com_finder/access.xml new file mode 100644 index 0000000..d646786 --- /dev/null +++ b/administrator/components/com_finder/access.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + +
+
diff --git a/administrator/components/com_finder/config.xml b/administrator/components/com_finder/config.xml new file mode 100644 index 0000000..1508d2a --- /dev/null +++ b/administrator/components/com_finder/config.xml @@ -0,0 +1,256 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
diff --git a/administrator/components/com_finder/controller.php b/administrator/components/com_finder/controller.php new file mode 100644 index 0000000..b233a65 --- /dev/null +++ b/administrator/components/com_finder/controller.php @@ -0,0 +1,60 @@ +input->get('view', 'index', 'word'); + $layout = $this->input->get('layout', 'index', 'word'); + $f_id = $this->input->get('filter_id', null, 'int'); + + // Check for edit form. + if ($view == 'filter' && $layout == 'edit' && !$this->checkEditId('com_finder.edit.filter', $f_id)) + { + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $f_id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_finder&view=filters', false)); + + return false; + } + + parent::display(); + + return $this; + } +} diff --git a/administrator/components/com_finder/controllers/filter.php b/administrator/components/com_finder/controllers/filter.php new file mode 100644 index 0000000..1ccbc92 --- /dev/null +++ b/administrator/components/com_finder/controllers/filter.php @@ -0,0 +1,241 @@ +input; + $lang = JFactory::getLanguage(); + $model = $this->getModel(); + $table = $model->getTable(); + $data = $input->post->get('jform', array(), 'array'); + $checkin = property_exists($table, 'checked_out'); + $context = "$this->option.edit.$this->context"; + $task = $this->getTask(); + + // Determine the name of the primary key for the data. + if (empty($key)) + { + $key = $table->getKeyName(); + } + + // To avoid data collisions the urlVar may be different from the primary key. + if (empty($urlVar)) + { + $urlVar = $key; + } + + $recordId = $input->get($urlVar, '', 'int'); + + if (!$this->checkEditId($context, $recordId)) + { + // Somehow the person just went to the form and tried to save it. We don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $recordId)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_list . $this->getRedirectToListAppend(), false)); + + return false; + } + + // Populate the row id from the session. + $data[$key] = $recordId; + + // The save2copy task needs to be handled slightly differently. + if ($task == 'save2copy') + { + // Check-in the original row. + if ($checkin && $model->checkin($data[$key]) === false) + { + // Check-in failed. Go back to the item and display a notice. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError())); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId, $urlVar)); + + return false; + } + + // Reset the ID and then treat the request as for Apply. + $data[$key] = 0; + $task = 'apply'; + } + + // Access check. + if (!$this->allowSave($data, $key)) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED')); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_list . $this->getRedirectToListAppend(), false)); + + return false; + } + + // Validate the posted data. + // Sometimes the form needs some posted data, such as for plugins and modules. + $form = $model->getForm($data, false); + + if (!$form) + { + $app->enqueueMessage($model->getError(), 'error'); + + return false; + } + + // Test whether the data is valid. + $validData = $model->validate($form, $data); + + // Check for validation errors. + if ($validData === false) + { + // Get the validation messages. + $errors = $model->getErrors(); + + // Push up to three validation messages out to the user. + for ($i = 0, $n = count($errors); $i < $n && $i < 3; $i++) + { + if (($errors[$i]) instanceof Exception) + { + $app->enqueueMessage($errors[$i]->getMessage(), 'warning'); + } + else + { + $app->enqueueMessage($errors[$i], 'warning'); + } + } + + // Save the data in the session. + $app->setUserState($context . '.data', $data); + + // Redirect back to the edit screen. + $this->setRedirect( + JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId, $key), false) + ); + + return false; + } + + // Get and sanitize the filter data. + $validData['data'] = $input->post->get('t', array(), 'array'); + $validData['data'] = array_unique($validData['data']); + JArrayHelper::toInteger($validData['data']); + + // Remove any values of zero. + if (array_search(0, $validData['data'], true)) + { + unset($validData['data'][array_search(0, $validData['data'], true)]); + } + + // Attempt to save the data. + if (!$model->save($validData)) + { + // Save the data in the session. + $app->setUserState($context . '.data', $validData); + + // Redirect back to the edit screen. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError())); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect( + JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId, $key), false) + ); + + return false; + } + + // Save succeeded, so check-in the record. + if ($checkin && $model->checkin($validData[$key]) === false) + { + // Save the data in the session. + $app->setUserState($context . '.data', $validData); + + // Check-in failed, so go back to the record and display a notice. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError())); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId, $key)); + + return false; + } + + $this->setMessage( + JText::_( + ($lang->hasKey($this->text_prefix . ($recordId == 0 && $app->isSite() ? '_SUBMIT' : '') . '_SAVE_SUCCESS') + ? $this->text_prefix : 'JLIB_APPLICATION') . ($recordId == 0 && $app->isSite() ? '_SUBMIT' : '') . '_SAVE_SUCCESS' + ) + ); + + // Redirect the user and adjust session state based on the chosen task. + switch ($task) + { + case 'apply': + // Set the record data in the session. + $recordId = $model->getState($this->context . '.id'); + $this->holdEditId($context, $recordId); + $app->setUserState($context . '.data', null); + $model->checkout($recordId); + + // Redirect back to the edit screen. + $this->setRedirect( + JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId, $key), false) + ); + + break; + + case 'save2new': + // Clear the record id and data from the session. + $this->releaseEditId($context, $recordId); + $app->setUserState($context . '.data', null); + + // Redirect back to the edit screen. + $this->setRedirect( + JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend(null, $key), false) + ); + + break; + + default: + // Clear the record id and data from the session. + $this->releaseEditId($context, $recordId); + $app->setUserState($context . '.data', null); + + // Redirect to the list screen. + $this->setRedirect( + JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_list . $this->getRedirectToListAppend(), false) + ); + + break; + } + + // Invoke the postSave method to allow for the child class to access the model. + $this->postSaveHook($model, $validData); + + return true; + } +} diff --git a/administrator/components/com_finder/controllers/filters.php b/administrator/components/com_finder/controllers/filters.php new file mode 100644 index 0000000..ea1184e --- /dev/null +++ b/administrator/components/com_finder/controllers/filters.php @@ -0,0 +1,37 @@ + true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } +} diff --git a/administrator/components/com_finder/controllers/index.html b/administrator/components/com_finder/controllers/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/controllers/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/controllers/index.php b/administrator/components/com_finder/controllers/index.php new file mode 100644 index 0000000..1df822f --- /dev/null +++ b/administrator/components/com_finder/controllers/index.php @@ -0,0 +1,70 @@ + true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } + + /** + * Method to purge all indexed links from the database. + * + * @return boolean True on success. + * + * @since 2.5 + */ + public function purge() + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Remove the script time limit. + @set_time_limit(0); + + $model = $this->getModel('Index', 'FinderModel'); + + // Attempt to purge the index. + $return = $model->purge(); + + if (!$return) + { + $message = JText::_('COM_FINDER_INDEX_PURGE_FAILED', $model->getError()); + $this->setRedirect('index.php?option=com_finder&view=index', $message); + return false; + } + else + { + $message = JText::_('COM_FINDER_INDEX_PURGE_SUCCESS'); + $this->setRedirect('index.php?option=com_finder&view=index', $message); + return true; + } + } +} diff --git a/administrator/components/com_finder/controllers/indexer.json.php b/administrator/components/com_finder/controllers/indexer.json.php new file mode 100644 index 0000000..1a269e5 --- /dev/null +++ b/administrator/components/com_finder/controllers/indexer.json.php @@ -0,0 +1,384 @@ +get('enable_logging', '0')) + { + if ($log == null) + { + $options['format'] = '{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}'; + $options['text_file'] = 'indexer.php'; + $log = JLog::addLogger($options); + } + } + + // Log the start + JLog::add('Starting the indexer', JLog::INFO); + + // We don't want this form to be cached. + header('Pragma: no-cache'); + header('Cache-Control: no-cache'); + header('Expires: -1'); + + // Check for a valid token. If invalid, send a 403 with the error message. + JSession::checkToken('request') or $this->sendResponse(new Exception(JText::_('JINVALID_TOKEN'), 403)); + + // Put in a buffer to silence noise. + ob_start(); + + // Reset the indexer state. + FinderIndexer::resetState(); + + // Import the finder plugins. + JPluginHelper::importPlugin('finder'); + + // Add the indexer language to JS + JText::script('COM_FINDER_AN_ERROR_HAS_OCCURRED'); + JText::script('COM_FINDER_NO_ERROR_RETURNED'); + + // Start the indexer. + try + { + // Trigger the onStartIndex event. + JEventDispatcher::getInstance()->trigger('onStartIndex'); + + // Get the indexer state. + $state = FinderIndexer::getState(); + $state->start = 1; + + // Send the response. + $this->sendResponse($state); + } + // Catch an exception and return the response. + catch (Exception $e) + { + $this->sendResponse($e); + } + } + + /** + * Method to run the next batch of content through the indexer. + * + * @return void + * + * @since 2.5 + */ + public function batch() + { + static $log; + + $params = JComponentHelper::getParams('com_finder'); + + if ($params->get('enable_logging', '0')) + { + if ($log == null) + { + $options['format'] = '{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}'; + $options['text_file'] = 'indexer.php'; + $log = JLog::addLogger($options); + } + } + + // Log the start + JLog::add('Starting the indexer batch process', JLog::INFO); + + // We don't want this form to be cached. + header('Pragma: no-cache'); + header('Cache-Control: no-cache'); + header('Expires: -1'); + + // Check for a valid token. If invalid, send a 403 with the error message. + JSession::checkToken('request') or $this->sendResponse(new Exception(JText::_('JINVALID_TOKEN'), 403)); + + // Put in a buffer to silence noise. + ob_start(); + + // Remove the script time limit. + @set_time_limit(0); + + // Get the indexer state. + $state = FinderIndexer::getState(); + + // Reset the batch offset. + $state->batchOffset = 0; + + // Update the indexer state. + FinderIndexer::setState($state); + + // Import the finder plugins. + JPluginHelper::importPlugin('finder'); + + /* + * We are going to swap out the raw document object with an HTML document + * in order to work around some plugins that don't do proper environment + * checks before trying to use HTML document functions. + */ + $raw = clone(JFactory::getDocument()); + $lang = JFactory::getLanguage(); + + // Get the document properties. + $attributes = array ( + 'charset' => 'utf-8', + 'lineend' => 'unix', + 'tab' => ' ', + 'language' => $lang->getTag(), + 'direction' => $lang->isRTL() ? 'rtl' : 'ltr' + ); + + // Get the HTML document. + $html = JDocument::getInstance('html', $attributes); + $doc = JFactory::getDocument(); + + // Swap the documents. + $doc = $html; + + // Get the admin application. + $admin = clone(JFactory::getApplication()); + + // Get the site app. + include_once JPATH_SITE . '/includes/application.php'; + $site = JApplication::getInstance('site'); + + // Swap the app. + $app = JFactory::getApplication(); + $app = $site; + + // Start the indexer. + try + { + // Trigger the onBeforeIndex event. + JEventDispatcher::getInstance()->trigger('onBeforeIndex'); + + // Trigger the onBuildIndex event. + JEventDispatcher::getInstance()->trigger('onBuildIndex'); + + // Get the indexer state. + $state = FinderIndexer::getState(); + $state->start = 0; + $state->complete = 0; + + // Swap the documents back. + $doc = $raw; + + // Swap the applications back. + $app = $admin; + + // Send the response. + $this->sendResponse($state); + } + // Catch an exception and return the response. + catch (Exception $e) + { + // Swap the documents back. + $doc = $raw; + + // Send the response. + $this->sendResponse($e); + } + } + + /** + * Method to optimize the index and perform any necessary cleanup. + * + * @return void + * + * @since 2.5 + */ + public function optimize() + { + // We don't want this form to be cached. + header('Pragma: no-cache'); + header('Cache-Control: no-cache'); + header('Expires: -1'); + + // Check for a valid token. If invalid, send a 403 with the error message. + JSession::checkToken('request') or $this->sendResponse(new Exception(JText::_('JINVALID_TOKEN'), 403)); + + // Put in a buffer to silence noise. + ob_start(); + + // Import the finder plugins. + JPluginHelper::importPlugin('finder'); + + try + { + // Optimize the index + FinderIndexer::getInstance()->optimize(); + + // Get the indexer state. + $state = FinderIndexer::getState(); + $state->start = 0; + $state->complete = 1; + + // Send the response. + $this->sendResponse($state); + } + // Catch an exception and return the response. + catch (Exception $e) + { + $this->sendResponse($e); + } + } + + /** + * Method to handle a send a JSON response. The body parameter + * can be a Exception object for when an error has occurred or + * a JObject for a good response. + * + * @param mixed $data JObject on success, Exception on error. [optional] + * + * @return void + * + * @since 2.5 + */ + public static function sendResponse($data = null) + { + static $log; + + $params = JComponentHelper::getParams('com_finder'); + + if ($params->get('enable_logging', '0')) + { + if ($log == null) + { + $options['format'] = '{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}'; + $options['text_file'] = 'indexer.php'; + $log = JLog::addLogger($options); + } + } + + // Send the assigned error code if we are catching an exception. + if ($data instanceof Exception) + { + JLog::add($data->getMessage(), JLog::ERROR); + JResponse::setHeader('status', $data->getCode()); + JResponse::sendHeaders(); + } + + // Create the response object. + $response = new FinderIndexerResponse($data); + + // Add the buffer. + $response->buffer = JDEBUG ? ob_get_contents() : ob_end_clean(); + + // Send the JSON response. + echo json_encode($response); + + // Close the application. + JFactory::getApplication()->close(); + } +} + +/** + * Finder Indexer JSON Response Class + * + * @package Joomla.Administrator + * @subpackage com_finder + * @since 2.5 + */ +class FinderIndexerResponse +{ + /** + * Class Constructor + * + * @param mixed $state The processing state for the indexer + * + * @since 2.5 + */ + public function __construct($state) + { + static $log; + + $params = JComponentHelper::getParams('com_finder'); + + if ($params->get('enable_logging', '0')) + { + if ($log == null) + { + $options['format'] = '{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}'; + $options['text_file'] = 'indexer.php'; + $log = JLog::addLogger($options); + } + } + + // The old token is invalid so send a new one. + $this->token = JFactory::getSession()->getFormToken(); + + // Check if we are dealing with an error. + if ($state instanceof Exception) + { + // Log the error + JLog::add($state->getMessage(), JLog::ERROR); + + // Prepare the error response. + $this->error = true; + $this->header = JText::_('COM_FINDER_INDEXER_HEADER_ERROR'); + $this->message = $state->getMessage(); + } + else + { + // Prepare the response data. + $this->batchSize = (int) $state->batchSize; + $this->batchOffset = (int) $state->batchOffset; + $this->totalItems = (int) $state->totalItems; + + $this->startTime = $state->startTime; + $this->endTime = JFactory::getDate()->toSQL(); + + $this->start = !empty($state->start) ? (int) $state->start : 0; + $this->complete = !empty($state->complete) ? (int) $state->complete : 0; + + // Set the appropriate messages. + if ($this->totalItems <= 0 && $this->complete) + { + $this->header = JText::_('COM_FINDER_INDEXER_HEADER_COMPLETE'); + $this->message = JText::_('COM_FINDER_INDEXER_MESSAGE_COMPLETE'); + } + elseif ($this->totalItems <= 0) + { + $this->header = JText::_('COM_FINDER_INDEXER_HEADER_OPTIMIZE'); + $this->message = JText::_('COM_FINDER_INDEXER_MESSAGE_OPTIMIZE'); + } + else + { + $this->header = JText::_('COM_FINDER_INDEXER_HEADER_RUNNING'); + $this->message = JText::_('COM_FINDER_INDEXER_MESSAGE_RUNNING'); + } + } + } +} + +// Register the error handler. +JError::setErrorHandling(E_ALL, 'callback', array('FinderControllerIndexer', 'sendResponse')); diff --git a/administrator/components/com_finder/controllers/maps.php b/administrator/components/com_finder/controllers/maps.php new file mode 100644 index 0000000..55c82be --- /dev/null +++ b/administrator/components/com_finder/controllers/maps.php @@ -0,0 +1,37 @@ + true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } +} diff --git a/administrator/components/com_finder/finder.php b/administrator/components/com_finder/finder.php new file mode 100644 index 0000000..6727751 --- /dev/null +++ b/administrator/components/com_finder/finder.php @@ -0,0 +1,19 @@ +authorise('core.manage', 'com_finder')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$controller = JControllerLegacy::getInstance('Finder'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_finder/finder.xml b/administrator/components/com_finder/finder.xml new file mode 100644 index 0000000..a749938 --- /dev/null +++ b/administrator/components/com_finder/finder.xml @@ -0,0 +1,64 @@ + + + com_finder + Joomla! Project + (C) 2005 - 2013 Open Source Matters. All rights reserved. + August 2011 + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_FINDER_XML_DESCRIPTION + COM_FINDER + + controller.php + index.html + finder.php + router.php + controllers + helpers + models + views + + + js + images + css + index.html + + + + sql/install.mysql.sql + sql/install.postgresql.sql + + + + + sql/uninstall.mysql.sql + sql/uninstall.postgresql.sql + + + + language/en-GB.com_finder.ini + + + + access.xml + config.xml + controller.php + finder.php + index.html + controllers + helpers + models + sql + tables + views + + + language/en-GB.com_finder.ini + language/en-GB.com_finder.sys.ini + + COM_FINDER + + diff --git a/administrator/components/com_finder/helpers/finder.php b/administrator/components/com_finder/helpers/finder.php new file mode 100644 index 0000000..f06deed --- /dev/null +++ b/administrator/components/com_finder/helpers/finder.php @@ -0,0 +1,77 @@ +set($action->name, $user->authorise($action->name, $assetName)); + } + + return $result; + } +} diff --git a/administrator/components/com_finder/helpers/html/finder.php b/administrator/components/com_finder/helpers/html/finder.php new file mode 100644 index 0000000..6f04660 --- /dev/null +++ b/administrator/components/com_finder/helpers/html/finder.php @@ -0,0 +1,125 @@ +getQuery(true) + ->select('DISTINCT t.title AS text, t.id AS value') + ->from($db->quoteName('#__finder_types') . ' AS t') + ->join('LEFT', $db->quoteName('#__finder_links') . ' AS l ON l.type_id = t.id') + ->order('t.title ASC'); + $db->setQuery($query); + + try + { + $rows = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + return; + } + + // Compile the options. + $options = array(); + + foreach ($rows as $row) + { + $key = $lang->hasKey(FinderHelperLanguage::branchPlural($row->text)) + ? FinderHelperLanguage::branchPlural($row->text) : $row->text; + $string = JText::sprintf('COM_FINDER_ITEM_X_ONLY', JText::_($key)); + $options[] = JHtml::_('select.option', $row->value, $string); + } + + return $options; + } + + /** + * Creates a list of maps. + * + * @return array An array containing the maps that can be selected. + * + * @since 2.5 + */ + public static function mapslist() + { + $lang = JFactory::getLanguage(); + + // Load the finder types. + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('title AS text, id AS value') + ->from($db->quoteName('#__finder_taxonomy')) + ->where($db->quoteName('parent_id') . ' = 1') + ->order('ordering, title ASC'); + $db->setQuery($query); + + try + { + $rows = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + return; + } + + // Compile the options. + $options = array(); + $options[] = JHtml::_('select.option', '1', JText::_('COM_FINDER_MAPS_BRANCHES')); + + foreach ($rows as $row) + { + $key = $lang->hasKey(FinderHelperLanguage::branchPlural($row->text)) + ? FinderHelperLanguage::branchPlural($row->text) : $row->text; + $string = JText::sprintf('COM_FINDER_ITEM_X_ONLY', JText::_($key)); + $options[] = JHtml::_('select.option', $row->value, $string); + } + + return $options; + } + + /** + * Creates a list of published states. + * + * @return array An array containing the states that can be selected. + * + * @since 2.5 + */ + public static function statelist() + { + $options = array(); + $options[] = JHtml::_('select.option', '1', JText::sprintf('COM_FINDER_ITEM_X_ONLY', JText::_('JPUBLISHED'))); + $options[] = JHtml::_('select.option', '0', JText::sprintf('COM_FINDER_ITEM_X_ONLY', JText::_('JUNPUBLISHED'))); + + return $options; + } +} diff --git a/administrator/components/com_finder/helpers/html/index.html b/administrator/components/com_finder/helpers/html/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/helpers/html/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/helpers/index.html b/administrator/components/com_finder/helpers/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/helpers/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/helpers/indexer/adapter.php b/administrator/components/com_finder/helpers/indexer/adapter.php new file mode 100644 index 0000000..829c463 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/adapter.php @@ -0,0 +1,930 @@ +db = JFactory::getDbo(); + + // Call the parent constructor. + parent::__construct($subject, $config); + + // Get the type id. + $this->type_id = $this->getTypeId(); + + // Add the content type if it doesn't exist and is set. + if (empty($this->type_id) && !empty($this->type_title)) + { + $this->type_id = FinderIndexerHelper::addContentType($this->type_title, $this->mime); + } + + // Check for a layout override. + if ($this->params->get('layout')) + { + $this->layout = $this->params->get('layout'); + } + + // Get the indexer object + $this->indexer = FinderIndexer::getInstance(); + } + + /** + * Method to get the adapter state and push it into the indexer. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on error. + */ + public function onStartIndex() + { + + // Get the indexer state. + $iState = FinderIndexer::getState(); + + // Get the number of content items. + $total = (int) $this->getContentCount(); + + // Add the content count to the total number of items. + $iState->totalItems += $total; + + // Populate the indexer state information for the adapter. + $iState->pluginState[$this->context]['total'] = $total; + $iState->pluginState[$this->context]['offset'] = 0; + + // Set the indexer state. + FinderIndexer::setState($iState); + } + + /** + * Method to prepare for the indexer to be run. This method will often + * be used to include dependencies and things of that nature. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on error. + */ + public function onBeforeIndex() + { + // Get the indexer and adapter state. + $iState = FinderIndexer::getState(); + $aState = $iState->pluginState[$this->context]; + + // Check the progress of the indexer and the adapter. + if ($iState->batchOffset == $iState->batchSize || $aState['offset'] == $aState['total']) + { + return true; + } + + // Run the setup method. + return $this->setup(); + } + + /** + * Method to index a batch of content items. This method can be called by + * the indexer many times throughout the indexing process depending on how + * much content is available for indexing. It is important to track the + * progress correctly so we can display it to the user. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on error. + */ + public function onBuildIndex() + { + // Get the indexer and adapter state. + $iState = FinderIndexer::getState(); + $aState = $iState->pluginState[$this->context]; + + // Check the progress of the indexer and the adapter. + if ($iState->batchOffset == $iState->batchSize || $aState['offset'] == $aState['total']) + { + return true; + } + + // Get the batch offset and size. + $offset = (int) $aState['offset']; + $limit = (int) ($iState->batchSize - $iState->batchOffset); + + // Get the content items to index. + $items = $this->getItems($offset, $limit); + + // Iterate through the items and index them. + for ($i = 0, $n = count($items); $i < $n; $i++) + { + // Index the item. + $this->index($items[$i]); + + // Adjust the offsets. + $offset++; + $iState->batchOffset++; + $iState->totalItems--; + } + + // Update the indexer state. + $aState['offset'] = $offset; + $iState->pluginState[$this->context] = $aState; + FinderIndexer::setState($iState); + + return true; + } + + /** + * Method to change the value of a content item's property in the links + * table. This is used to synchronize published and access states that + * are changed when not editing an item directly. + * + * @param string $id The ID of the item to change. + * @param string $property The property that is being changed. + * @param integer $value The new value of that property. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function change($id, $property, $value) + { + // Check for a property we know how to handle. + if ($property !== 'state' && $property !== 'access') + { + return true; + } + + // Get the url for the content id. + $item = $this->db->quote($this->getUrl($id, $this->extension, $this->layout)); + + // Update the content items. + $query = $this->db->getQuery(true) + ->update($this->db->quoteName('#__finder_links')) + ->set($this->db->quoteName($property) . ' = ' . (int) $value) + ->where($this->db->quoteName('url') . ' = ' . $item); + $this->db->setQuery($query); + $this->db->execute(); + + return true; + } + + /** + * Method to index an item. + * + * @param FinderIndexerResult $item The item to index as a FinderIndexerResult object. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + abstract protected function index(FinderIndexerResult $item); + + /** + * Method to reindex an item. + * + * @param integer $id The ID of the item to reindex. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function reindex($id) + { + // Run the setup method. + $this->setup(); + + // Get the item. + $item = $this->getItem($id); + + // Index the item. + $this->index($item); + } + + /** + * Method to remove an item from the index. + * + * @param string $id The ID of the item to remove. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function remove($id) + { + // Get the item's URL + $url = $this->db->quote($this->getUrl($id, $this->extension, $this->layout)); + + // Get the link ids for the content items. + $query = $this->db->getQuery(true) + ->select($this->db->quoteName('link_id')) + ->from($this->db->quoteName('#__finder_links')) + ->where($this->db->quoteName('url') . ' = ' . $url); + $this->db->setQuery($query); + $items = $this->db->loadColumn(); + + // Check the items. + if (empty($items)) + { + return true; + } + + // Remove the items. + foreach ($items as $item) + { + $this->indexer->remove($item); + } + + return true; + } + + /** + * Method to setup the adapter before indexing. + * + * @return boolean True on success, false on failure. + * + * @since 2.5 + * @throws Exception on database error. + */ + abstract protected function setup(); + + /** + * Method to update index data on category access level changes + * + * @param JTable $row A JTable object + * + * @return void + * + * @since 2.5 + */ + protected function categoryAccessChange($row) + { + $query = clone($this->getStateQuery()); + $query->where('c.id = ' . (int) $row->id); + + // Get the access level. + $this->db->setQuery($query); + $items = $this->db->loadObjectList(); + + // Adjust the access level for each item within the category. + foreach ($items as $item) + { + // Set the access level. + $temp = max($item->access, $row->access); + + // Update the item. + $this->change((int) $item->id, 'access', $temp); + + // Reindex the item + $this->reindex($row->id); + } + } + + /** + * Method to update index data on category access level changes + * + * @param array $pks A list of primary key ids of the content that has changed state. + * @param integer $value The value of the state that the content has been changed to. + * + * @return void + * + * @since 2.5 + */ + protected function categoryStateChange($pks, $value) + { + /* + * The item's published state is tied to the category + * published state so we need to look up all published states + * before we change anything. + */ + foreach ($pks as $pk) + { + $query = clone($this->getStateQuery()); + $query->where('c.id = ' . (int) $pk); + + // Get the published states. + $this->db->setQuery($query); + $items = $this->db->loadObjectList(); + + // Adjust the state for each item within the category. + foreach ($items as $item) + { + // Translate the state. + $temp = $this->translateState($item->state, $value); + + // Update the item. + $this->change($item->id, 'state', $temp); + + // Reindex the item + $this->reindex($item->id); + } + } + } + + /** + * Method to check the existing access level for categories + * + * @param JTable $row A JTable object + * + * @return void + * + * @since 2.5 + */ + protected function checkCategoryAccess($row) + { + $query = $this->db->getQuery(true) + ->select($this->db->quoteName('access')) + ->from($this->db->quoteName('#__categories')) + ->where($this->db->quoteName('id') . ' = ' . (int) $row->id); + $this->db->setQuery($query); + + // Store the access level to determine if it changes + $this->old_cataccess = $this->db->loadResult(); + } + + /** + * Method to check the existing access level for items + * + * @param JTable $row A JTable object + * + * @return void + * + * @since 2.5 + */ + protected function checkItemAccess($row) + { + $query = $this->db->getQuery(true) + ->select($this->db->quoteName('access')) + ->from($this->db->quoteName($this->table)) + ->where($this->db->quoteName('id') . ' = ' . (int) $row->id); + $this->db->setQuery($query); + + // Store the access level to determine if it changes + $this->old_access = $this->db->loadResult(); + } + + /** + * Method to get the number of content items available to index. + * + * @return integer The number of content items available to index. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function getContentCount() + { + $return = 0; + + // Get the list query. + $query = $this->getListQuery(); + + // Check if the query is valid. + if (empty($query)) + { + return $return; + } + + // Tweak the SQL query to make the total lookup faster. + if ($query instanceof JDatabaseQuery) + { + $query = clone($query); + $query->clear('select') + ->select('COUNT(*)') + ->clear('order'); + } + + // Get the total number of content items to index. + $this->db->setQuery($query); + $return = (int) $this->db->loadResult(); + + return $return; + } + + /** + * Method to get a content item to index. + * + * @param integer $id The id of the content item. + * + * @return FinderIndexerResult A FinderIndexerResult object. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function getItem($id) + { + // Get the list query and add the extra WHERE clause. + $query = $this->getListQuery(); + $query->where('a.id = ' . (int) $id); + + // Get the item to index. + $this->db->setQuery($query); + $row = $this->db->loadAssoc(); + + // Convert the item to a result object. + $item = JArrayHelper::toObject($row, 'FinderIndexerResult'); + + // Set the item type. + $item->type_id = $this->type_id; + + // Set the item layout. + $item->layout = $this->layout; + + return $item; + } + + /** + * Method to get a list of content items to index. + * + * @param integer $offset The list offset. + * @param integer $limit The list limit. + * @param JDatabaseQuery $query A JDatabaseQuery object. [optional] + * + * @return array An array of FinderIndexerResult objects. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function getItems($offset, $limit, $query = null) + { + $items = array(); + + // Get the content items to index. + $this->db->setQuery($this->getListQuery($query), $offset, $limit); + $rows = $this->db->loadAssocList(); + + // Convert the items to result objects. + foreach ($rows as $row) + { + // Convert the item to a result object. + $item = JArrayHelper::toObject($row, 'FinderIndexerResult'); + + // Set the item type. + $item->type_id = $this->type_id; + + // Set the mime type. + $item->mime = $this->mime; + + // Set the item layout. + $item->layout = $this->layout; + + // Set the extension if present + if (isset($row->extension)) + { + $item->extension = $row->extension; + } + + // Add the item to the stack. + $items[] = $item; + } + + return $items; + } + + /** + * Method to get the SQL query used to retrieve the list of content items. + * + * @param mixed $query A JDatabaseQuery object. [optional] + * + * @return JDatabaseQuery A database object. + * + * @since 2.5 + */ + protected function getListQuery($query = null) + { + // Check if we can use the supplied SQL query. + $query = $query instanceof JDatabaseQuery ? $query : $this->db->getQuery(true); + + return $query; + } + + /** + * Method to get the plugin type + * + * @param integer $id The plugin ID + * + * @return string The plugin type + * + * @since 2.5 + */ + protected function getPluginType($id) + { + // Prepare the query + $query = $this->db->getQuery(true) + ->select($this->db->quoteName('element')) + ->from($this->db->quoteName('#__extensions')) + ->where($this->db->quoteName('extension_id') . ' = ' . (int) $id); + $this->db->setQuery($query); + $type = $this->db->loadResult(); + + return $type; + } + + /** + * Method to get a SQL query to load the published and access states for + * an article and category. + * + * @return JDatabaseQuery A database object. + * + * @since 2.5 + */ + protected function getStateQuery() + { + $query = $this->db->getQuery(true); + + // Item ID + $query->select('a.id'); + + // Item and category published state + $query->select('a.' . $this->state_field . ' AS state, c.published AS cat_state'); + + // Item and category access levels + $query->select('a.access, c.access AS cat_access') + ->from($this->table . ' AS a') + ->join('LEFT', '#__categories AS c ON c.id = a.catid'); + + return $query; + } + + /** + * Method to get the query clause for getting items to update by time. + * + * @param string $time The modified timestamp. + * + * @return JDatabaseQuery A database object. + * + * @since 2.5 + */ + protected function getUpdateQueryByTime($time) + { + // Build an SQL query based on the modified time. + $query = $this->db->getQuery(true) + ->where('a.modified >= ' . $this->db->quote($time)); + + return $query; + } + + /** + * Method to get the query clause for getting items to update by id. + * + * @param array $ids The ids to load. + * + * @return JDatabaseQuery A database object. + * + * @since 2.5 + */ + protected function getUpdateQueryByIds($ids) + { + // Build an SQL query based on the item ids. + $query = $this->db->getQuery(true) + ->where('a.id IN(' . implode(',', $ids) . ')'); + + return $query; + } + + /** + * Method to get the type id for the adapter content. + * + * @return integer The numeric type id for the content. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function getTypeId() + { + // Get the type id from the database. + $query = $this->db->getQuery(true) + ->select($this->db->quoteName('id')) + ->from($this->db->quoteName('#__finder_types')) + ->where($this->db->quoteName('title') . ' = ' . $this->db->quote($this->type_title)); + $this->db->setQuery($query); + $result = (int) $this->db->loadResult(); + + return $result; + } + + /** + * Method to get the URL for the item. The URL is how we look up the link + * in the Finder index. + * + * @param integer $id The id of the item. + * @param string $extension The extension the category is in. + * @param string $view The view for the URL. + * + * @return string The URL of the item. + * + * @since 2.5 + */ + protected function getURL($id, $extension, $view) + { + return 'index.php?option=' . $extension . '&view=' . $view . '&id=' . $id; + } + + /** + * Method to get the page title of any menu item that is linked to the + * content item, if it exists and is set. + * + * @param string $url The url of the item. + * + * @return mixed The title on success, null if not found. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function getItemMenuTitle($url) + { + $return = null; + + // Set variables + $user = JFactory::getUser(); + $groups = implode(',', $user->getAuthorisedViewLevels()); + + // Build a query to get the menu params. + $query = $this->db->getQuery(true) + ->select($this->db->quoteName('params')) + ->from($this->db->quoteName('#__menu')) + ->where($this->db->quoteName('link') . ' = ' . $this->db->quote($url)) + ->where($this->db->quoteName('published') . ' = 1') + ->where($this->db->quoteName('access') . ' IN (' . $groups . ')'); + + // Get the menu params from the database. + $this->db->setQuery($query); + $params = $this->db->loadResult(); + + // Check the results. + if (empty($params)) + { + return $return; + } + + // Instantiate the params. + $params = json_decode($params); + + // Get the page title if it is set. + if ($params->page_title) + { + $return = $params->page_title; + } + + return $return; + } + + /** + * Method to update index data on access level changes + * + * @param JTable $row A JTable object + * + * @return void + * + * @since 2.5 + */ + protected function itemAccessChange($row) + { + $query = clone($this->getStateQuery()); + $query->where('a.id = ' . (int) $row->id); + + // Get the access level. + $this->db->setQuery($query); + $item = $this->db->loadObject(); + + // Set the access level. + $temp = max($row->access, $item->cat_access); + + // Update the item. + $this->change((int) $row->id, 'access', $temp); + } + + /** + * Method to update index data on published state changes + * + * @param array $pks A list of primary key ids of the content that has changed state. + * @param integer $value The value of the state that the content has been changed to. + * + * @return void + * + * @since 2.5 + */ + protected function itemStateChange($pks, $value) + { + /* + * The item's published state is tied to the category + * published state so we need to look up all published states + * before we change anything. + */ + foreach ($pks as $pk) + { + $query = clone($this->getStateQuery()); + $query->where('a.id = ' . (int) $pk); + + // Get the published states. + $this->db->setQuery($query); + $item = $this->db->loadObject(); + + // Translate the state. + $temp = $this->translateState($value, $item->cat_state); + + // Update the item. + $this->change($pk, 'state', $temp); + + // Reindex the item + $this->reindex($pk); + } + } + + /** + * Method to update index data when a plugin is disabled + * + * @param array $pks A list of primary key ids of the content that has changed state. + * + * @return void + * + * @since 2.5 + */ + protected function pluginDisable($pks) + { + // Since multiple plugins may be disabled at a time, we need to check first + // that we're handling the appropriate one for the context + foreach ($pks as $pk) + { + if ($this->getPluginType($pk) == strtolower($this->context)) + { + // Get all of the items to unindex them + $query = clone($this->getStateQuery()); + $this->db->setQuery($query); + $items = $this->db->loadColumn(); + + // Remove each item + foreach ($items as $item) + { + $this->remove($item); + } + } + } + } + + /** + * Method to translate the native content states into states that the + * indexer can use. + * + * @param integer $item The item state. + * @param integer $category The category state. [optional] + * + * @return integer The translated indexer state. + * + * @since 2.5 + */ + protected function translateState($item, $category = null) + { + // If category is present, factor in its states as well + if ($category !== null) + { + if ($category == 0) + { + $item = 0; + } + } + + // Translate the state + switch ($item) + { + // Published and archived items only should return a published state + case 1; + case 2: + return 1; + + // All other states should return a unpublished state + default: + case 0: + return 0; + } + } +} diff --git a/administrator/components/com_finder/helpers/indexer/driver/index.html b/administrator/components/com_finder/helpers/indexer/driver/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/driver/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/helpers/indexer/driver/mysql.php b/administrator/components/com_finder/helpers/indexer/driver/mysql.php new file mode 100644 index 0000000..6386d6f --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/driver/mysql.php @@ -0,0 +1,663 @@ +mark('beforeIndexing') : null; + $db = JFactory::getDbo(); + $nd = $db->getNullDate(); + + // Check if the item is in the database. + $query = $db->getQuery(true) + ->select($db->quoteName('link_id') . ', ' . $db->quoteName('md5sum')) + ->from($db->quoteName('#__finder_links')) + ->where($db->quoteName('url') . ' = ' . $db->quote($item->url)); + + // Load the item from the database. + $db->setQuery($query); + $link = $db->loadObject(); + + // Get the indexer state. + $state = static::getState(); + + // Get the signatures of the item. + $curSig = static::getSignature($item); + $oldSig = isset($link->md5sum) ? $link->md5sum : null; + + // Get the other item information. + $linkId = empty($link->link_id) ? null : $link->link_id; + $isNew = empty($link->link_id) ? true : false; + + // Check the signatures. If they match, the item is up to date. + if (!$isNew && $curSig == $oldSig) + { + return $linkId; + } + + /* + * If the link already exists, flush all the term maps for the item. + * Maps are stored in 16 tables so we need to iterate through and flush + * each table one at a time. + */ + if (!$isNew) + { + for ($i = 0; $i <= 15; $i++) + { + // Flush the maps for the link. + $query->clear() + ->delete($db->quoteName('#__finder_links_terms' . dechex($i))) + ->where($db->quoteName('link_id') . ' = ' . (int) $linkId); + $db->setQuery($query); + $db->execute(); + } + + // Remove the taxonomy maps. + FinderIndexerTaxonomy::removeMaps($linkId); + } + + // Mark afterUnmapping in the profiler. + static::$profiler ? static::$profiler->mark('afterUnmapping') : null; + + // Perform cleanup on the item data. + $item->publish_start_date = (int) $item->publish_start_date != 0 ? $item->publish_start_date : $nd; + $item->publish_end_date = (int) $item->publish_end_date != 0 ? $item->publish_end_date : $nd; + $item->start_date = (int) $item->start_date != 0 ? $item->start_date : $nd; + $item->end_date = (int) $item->end_date != 0 ? $item->end_date : $nd; + + // Prepare the item description. + $item->description = FinderIndexerHelper::parse($item->summary); + + /* + * Now, we need to enter the item into the links table. If the item + * already exists in the database, we need to use an UPDATE query. + * Otherwise, we need to use an INSERT to get the link id back. + */ + + if ($isNew) + { + $columnsArray = array( + $db->quoteName('url'), $db->quoteName('route'), $db->quoteName('title'), $db->quoteName('description'), + $db->quoteName('indexdate'), $db->quoteName('published'), $db->quoteName('state'), $db->quoteName('access'), + $db->quoteName('language'), $db->quoteName('type_id'), $db->quoteName('object'), $db->quoteName('publish_start_date'), + $db->quoteName('publish_end_date'), $db->quoteName('start_date'), $db->quoteName('end_date'), $db->quoteName('list_price'), + $db->quoteName('sale_price') + ); + + // Insert the link. + $query->clear() + ->insert($db->quoteName('#__finder_links')) + ->columns($columnsArray) + ->values( + $db->quote($item->url) . ', ' + . $db->quote($item->route) . ', ' + . $db->quote($item->title) . ', ' + . $db->quote($item->description) . ', ' + . $query->currentTimestamp() . ', ' + . '1, ' + . (int) $item->state . ', ' + . (int) $item->access . ', ' + . $db->quote($item->language) . ', ' + . (int) $item->type_id . ', ' + . $db->quote(serialize($item)) . ', ' + . $db->quote($item->publish_start_date) . ', ' + . $db->quote($item->publish_end_date) . ', ' + . $db->quote($item->start_date) . ', ' + . $db->quote($item->end_date) . ', ' + . (double) ($item->list_price ? $item->list_price : 0) . ', ' + . (double) ($item->sale_price ? $item->sale_price : 0) + ); + $db->setQuery($query); + $db->execute(); + + // Get the link id. + $linkId = (int) $db->insertid(); + } + else + { + // Update the link. + $query->clear() + ->update($db->quoteName('#__finder_links')) + ->set($db->quoteName('route') . ' = ' . $db->quote($item->route)) + ->set($db->quoteName('title') . ' = ' . $db->quote($item->title)) + ->set($db->quoteName('description') . ' = ' . $db->quote($item->description)) + ->set($db->quoteName('indexdate') . ' = ' . $query->currentTimestamp()) + ->set($db->quoteName('state') . ' = ' . (int) $item->state) + ->set($db->quoteName('access') . ' = ' . (int) $item->access) + ->set($db->quoteName('language') . ' = ' . $db->quote($item->language)) + ->set($db->quoteName('type_id') . ' = ' . (int) $item->type_id) + ->set($db->quoteName('object') . ' = ' . $db->quote(serialize($item))) + ->set($db->quoteName('publish_start_date') . ' = ' . $db->quote($item->publish_start_date)) + ->set($db->quoteName('publish_end_date') . ' = ' . $db->quote($item->publish_end_date)) + ->set($db->quoteName('start_date') . ' = ' . $db->quote($item->start_date)) + ->set($db->quoteName('end_date') . ' = ' . $db->quote($item->end_date)) + ->set($db->quoteName('list_price') . ' = ' . (double) ($item->list_price ? $item->list_price : 0)) + ->set($db->quoteName('sale_price') . ' = ' . (double) ($item->sale_price ? $item->sale_price : 0)) + ->where('link_id = ' . (int) $linkId); + $db->setQuery($query); + $db->execute(); + } + + // Set up the variables we will need during processing. + $count = 0; + + // Mark afterLinking in the profiler. + static::$profiler ? static::$profiler->mark('afterLinking') : null; + + // Truncate the tokens tables. + $db->truncateTable('#__finder_tokens'); + + // Truncate the tokens aggregate table. + $db->truncateTable('#__finder_tokens_aggregate'); + + /* + * Process the item's content. The items can customize their + * processing instructions to define extra properties to process + * or rearrange how properties are weighted. + */ + foreach ($item->getInstructions() as $group => $properties) + { + // Iterate through the properties of the group. + foreach ($properties as $property) + { + // Check if the property exists in the item. + if (empty($item->$property)) + { + continue; + } + + // Tokenize the property. + if (is_array($item->$property)) + { + // Tokenize an array of content and add it to the database. + foreach ($item->$property as $ip) + { + /* + * If the group is path, we need to a few extra processing + * steps to strip the extension and convert slashes and dashes + * to spaces. + */ + if ($group === static::PATH_CONTEXT) + { + $ip = JFile::stripExt($ip); + $ip = str_replace('/', ' ', $ip); + $ip = str_replace('-', ' ', $ip); + } + + // Tokenize a string of content and add it to the database. + $count += $this->tokenizeToDB($ip, $group, $item->language, $format); + + // Check if we're approaching the memory limit of the token table. + if ($count > static::$state->options->get('memory_table_limit', 30000)) + { + $this->toggleTables(false); + } + } + } + else + { + /* + * If the group is path, we need to a few extra processing + * steps to strip the extension and convert slashes and dashes + * to spaces. + */ + if ($group === static::PATH_CONTEXT) + { + $item->$property = JFile::stripExt($item->$property); + $item->$property = str_replace('/', ' ', $item->$property); + $item->$property = str_replace('-', ' ', $item->$property); + } + + // Tokenize a string of content and add it to the database. + $count += $this->tokenizeToDB($item->$property, $group, $item->language, $format); + + // Check if we're approaching the memory limit of the token table. + if ($count > static::$state->options->get('memory_table_limit', 30000)) + { + $this->toggleTables(false); + } + } + } + } + + /* + * Process the item's taxonomy. The items can customize their + * taxonomy mappings to define extra properties to map. + */ + foreach ($item->getTaxonomy() as $branch => $nodes) + { + // Iterate through the nodes and map them to the branch. + foreach ($nodes as $node) + { + // Add the node to the tree. + $nodeId = FinderIndexerTaxonomy::addNode($branch, $node->title, $node->state, $node->access); + + // Add the link => node map. + FinderIndexerTaxonomy::addMap($linkId, $nodeId); + + // Tokenize the node title and add them to the database. + $count += $this->tokenizeToDB($node->title, static::META_CONTEXT, $item->language, $format); + } + } + + // Mark afterProcessing in the profiler. + static::$profiler ? static::$profiler->mark('afterProcessing') : null; + + /* + * At this point, all of the item's content has been parsed, tokenized + * and inserted into the #__finder_tokens table. Now, we need to + * aggregate all the data into that table into a more usable form. The + * aggregated data will be inserted into #__finder_tokens_aggregate + * table. + */ + $query = 'INSERT INTO ' . $db->quoteName('#__finder_tokens_aggregate') . + ' (' . $db->quoteName('term_id') . + ', ' . $db->quoteName('term') . + ', ' . $db->quoteName('stem') . + ', ' . $db->quoteName('common') . + ', ' . $db->quoteName('phrase') . + ', ' . $db->quoteName('term_weight') . + ', ' . $db->quoteName('context') . + ', ' . $db->quoteName('context_weight') . + ', ' . $db->quoteName('language') . ')' . + ' SELECT' . + ' t.term_id, t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, ' . + ' ROUND( t1.weight * COUNT( t2.term ) * %F, 8 ) AS context_weight, t1.language' . + ' FROM (' . + ' SELECT DISTINCT t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, t1.language' . + ' FROM ' . $db->quoteName('#__finder_tokens') . ' AS t1' . + ' WHERE t1.context = %d' . + ' ) AS t1' . + ' JOIN ' . $db->quoteName('#__finder_tokens') . ' AS t2 ON t2.term = t1.term' . + ' LEFT JOIN ' . $db->quoteName('#__finder_terms') . ' AS t ON t.term = t1.term' . + ' WHERE t2.context = %d' . + ' GROUP BY t1.term' . + ' ORDER BY t1.term DESC'; + + // Iterate through the contexts and aggregate the tokens per context. + foreach ($state->weights as $context => $multiplier) + { + // Run the query to aggregate the tokens for this context.. + $db->setQuery(sprintf($query, $multiplier, $context, $context)); + $db->execute(); + } + + // Mark afterAggregating in the profiler. + static::$profiler ? static::$profiler->mark('afterAggregating') : null; + + /* + * When we pulled down all of the aggregate data, we did a LEFT JOIN + * over the terms table to try to find all the term ids that + * already exist for our tokens. If any of the rows in the aggregate + * table have a term of 0, then no term record exists for that + * term so we need to add it to the terms table. + */ + $db->setQuery( + 'INSERT IGNORE INTO ' . $db->quoteName('#__finder_terms') . + ' (' . $db->quoteName('term') . + ', ' . $db->quoteName('stem') . + ', ' . $db->quoteName('common') . + ', ' . $db->quoteName('phrase') . + ', ' . $db->quoteName('weight') . + ', ' . $db->quoteName('soundex') . + ', ' . $db->quoteName('language') . ')' . + ' SELECT ta.term, ta.stem, ta.common, ta.phrase, ta.term_weight, SOUNDEX(ta.term), ta.language' . + ' FROM ' . $db->quoteName('#__finder_tokens_aggregate') . ' AS ta' . + ' WHERE ta.term_id = 0' . + ' GROUP BY ta.term' + ); + $db->execute(); + + /* + * Now, we just inserted a bunch of new records into the terms table + * so we need to go back and update the aggregate table with all the + * new term ids. + */ + $query = $db->getQuery(true) + ->update($db->quoteName('#__finder_tokens_aggregate') . ' AS ta') + ->join('INNER', $db->quoteName('#__finder_terms') . ' AS t ON t.term = ta.term') + ->set('ta.term_id = t.term_id') + ->where('ta.term_id = 0'); + $db->setQuery($query); + $db->execute(); + + // Mark afterTerms in the profiler. + static::$profiler ? static::$profiler->mark('afterTerms') : null; + + /* + * After we've made sure that all of the terms are in the terms table + * and the aggregate table has the correct term ids, we need to update + * the links counter for each term by one. + */ + $query->clear() + ->update($db->quoteName('#__finder_terms') . ' AS t') + ->join('INNER', $db->quoteName('#__finder_tokens_aggregate') . ' AS ta ON ta.term_id = t.term_id') + ->set('t.' . $db->quoteName('links') . ' = t.links + 1'); + $db->setQuery($query); + $db->execute(); + + // Mark afterTerms in the profiler. + static::$profiler ? static::$profiler->mark('afterTerms') : null; + + /* + * Before we can insert all of the mapping rows, we have to figure out + * which mapping table the rows need to be inserted into. The mapping + * table for each term is based on the first character of the md5 of + * the first character of the term. In php, it would be expressed as + * substr(md5(substr($token, 0, 1)), 0, 1) + */ + $query->clear() + ->update($db->quoteName('#__finder_tokens_aggregate')) + ->set($db->quoteName('map_suffix') . ' = SUBSTR(MD5(SUBSTR(' . $db->quoteName('term') . ', 1, 1)), 1, 1)'); + $db->setQuery($query); + $db->execute(); + + /* + * At this point, the aggregate table contains a record for each + * term in each context. So, we're going to pull down all of that + * data while grouping the records by term and add all of the + * sub-totals together to arrive at the final total for each token for + * this link. Then, we insert all of that data into the appropriate + * mapping table. + */ + for ($i = 0; $i <= 15; $i++) + { + // Get the mapping table suffix. + $suffix = dechex($i); + + /* + * We have to run this query 16 times, one for each link => term + * mapping table. + */ + $db->setQuery( + 'INSERT INTO ' . $db->quoteName('#__finder_links_terms' . $suffix) . + ' (' . $db->quoteName('link_id') . + ', ' . $db->quoteName('term_id') . + ', ' . $db->quoteName('weight') . ')' . + ' SELECT ' . (int) $linkId . ', ' . $db->quoteName('term_id') . ',' . + ' ROUND(SUM(' . $db->quoteName('context_weight') . '), 8)' . + ' FROM ' . $db->quoteName('#__finder_tokens_aggregate') . + ' WHERE ' . $db->quoteName('map_suffix') . ' = ' . $db->quote($suffix) . + ' GROUP BY ' . $db->quoteName('term') . + ' ORDER BY ' . $db->quoteName('term') . ' DESC' + ); + $db->execute(); + } + + // Mark afterMapping in the profiler. + static::$profiler ? static::$profiler->mark('afterMapping') : null; + + // Update the signature. + $query->clear() + ->update($db->quoteName('#__finder_links')) + ->set($db->quoteName('md5sum') . ' = ' . $db->quote($curSig)) + ->where($db->quoteName('link_id') . ' = ' . $db->quote($linkId)); + $db->setQuery($query); + $db->execute(); + + // Mark afterSigning in the profiler. + static::$profiler ? static::$profiler->mark('afterSigning') : null; + + // Truncate the tokens tables. + $db->truncateTable('#__finder_tokens'); + + // Truncate the tokens aggregate table. + $db->truncateTable('#__finder_tokens_aggregate'); + + // Toggle the token tables back to memory tables. + $this->toggleTables(true); + + // Mark afterTruncating in the profiler. + static::$profiler ? static::$profiler->mark('afterTruncating') : null; + + return $linkId; + } + + /** + * Method to remove a link from the index. + * + * @param integer $linkId The id of the link. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + public function remove($linkId) + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + // Update the link counts and remove the mapping records. + for ($i = 0; $i <= 15; $i++) + { + // Update the link counts for the terms. + $query->update($db->quoteName('#__finder_terms') . ' AS t') + ->join('INNER', $db->quoteName('#__finder_links_terms' . dechex($i)) . ' AS m ON m.term_id = t.term_id') + ->set('t.links = t.links - 1') + ->where('m.link_id = ' . $db->quote((int) $linkId)); + $db->setQuery($query); + $db->execute(); + + // Remove all records from the mapping tables. + $query->clear() + ->delete($db->quoteName('#__finder_links_terms' . dechex($i))) + ->where($db->quoteName('link_id') . ' = ' . (int) $linkId); + $db->setQuery($query); + $db->execute(); + } + + // Delete all orphaned terms. + $query->clear() + ->delete($db->quoteName('#__finder_terms')) + ->where($db->quoteName('links') . ' <= 0'); + $db->setQuery($query); + $db->execute(); + + // Delete the link from the index. + $query->clear() + ->delete($db->quoteName('#__finder_links')) + ->where($db->quoteName('link_id') . ' = ' . $db->quote((int) $linkId)); + $db->setQuery($query); + $db->execute(); + + // Remove the taxonomy maps. + FinderIndexerTaxonomy::removeMaps($linkId); + + // Remove the orphaned taxonomy nodes. + FinderIndexerTaxonomy::removeOrphanNodes(); + + return true; + } + + /** + * Method to optimize the index. We use this method to remove unused terms + * and any other optimizations that might be necessary. + * + * @return boolean True on success. + * + * @since 3.0 + * @throws Exception on database error. + */ + public function optimize() + { + // Get the database object. + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + // Delete all orphaned terms. + $query->delete($db->quoteName('#__finder_terms')) + ->where($db->quoteName('links') . ' <= 0'); + $db->setQuery($query); + $db->execute(); + + // Optimize the links table. + $db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__finder_links')); + $db->execute(); + + for ($i = 0; $i <= 15; $i++) + { + // Optimize the terms mapping table. + $db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__finder_links_terms' . dechex($i))); + $db->execute(); + } + + // Optimize the terms mapping table. + $db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__finder_links_terms')); + $db->execute(); + + // Remove the orphaned taxonomy nodes. + FinderIndexerTaxonomy::removeOrphanNodes(); + + // Optimize the taxonomy mapping table. + $db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__finder_taxonomy_map')); + $db->execute(); + + return true; + } + + /** + * Method to add a set of tokens to the database. + * + * @param mixed $tokens An array or single FinderIndexerToken object. + * @param mixed $context The context of the tokens. See context constants. [optional] + * + * @return integer The number of tokens inserted into the database. + * + * @since 3.0 + * @throws Exception on database error. + */ + protected function addTokensToDB($tokens, $context = '') + { + // Get the database object. + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + // Force tokens to an array. + $tokens = is_array($tokens) ? $tokens : array($tokens); + + // Count the number of token values. + $values = 0; + + // Insert the tokens into the database. + $query->insert($db->quoteName('#__finder_tokens')) + ->columns( + array( + $db->quoteName('term'), + $db->quoteName('stem'), + $db->quoteName('common'), + $db->quoteName('phrase'), + $db->quoteName('weight'), + $db->quoteName('context'), + $db->quoteName('language') + ) + ); + + // Iterate through the tokens to create SQL value sets. + foreach ($tokens as $token) + { + $query->values( + $db->quote($token->term) . ', ' + . $db->quote($token->stem) . ', ' + . (int) $token->common . ', ' + . (int) $token->phrase . ', ' + . (float) $token->weight . ', ' + . (int) $context . ', ' + . $db->quote($token->language) + ); + $values++; + } + $db->setQuery($query); + $db->execute(); + + return $values; + } + + /** + * Method to switch the token tables from Memory tables to MyISAM tables + * when they are close to running out of memory. + * + * @param boolean $memory Flag to control how they should be toggled. + * + * @return boolean True on success. + * + * @since 3.0 + * @throws Exception on database error. + */ + protected function toggleTables($memory) + { + static $state; + + // Get the database adapter. + $db = JFactory::getDbo(); + + // Check if we are setting the tables to the Memory engine. + if ($memory === true && $state !== true) + { + // Set the tokens table to Memory. + $db->setQuery('ALTER TABLE ' . $db->quoteName('#__finder_tokens') . ' ENGINE = MEMORY'); + $db->execute(); + + // Set the tokens aggregate table to Memory. + $db->setQuery('ALTER TABLE ' . $db->quoteName('#__finder_tokens_aggregate') . ' ENGINE = MEMORY'); + $db->execute(); + + // Set the internal state. + $state = $memory; + } + // We must be setting the tables to the MyISAM engine. + elseif ($memory === false && $state !== false) + { + // Set the tokens table to MyISAM. + $db->setQuery('ALTER TABLE ' . $db->quoteName('#__finder_tokens') . ' ENGINE = MYISAM'); + $db->execute(); + + // Set the tokens aggregate table to MyISAM. + $db->setQuery('ALTER TABLE ' . $db->quoteName('#__finder_tokens_aggregate') . ' ENGINE = MYISAM'); + $db->execute(); + + // Set the internal state. + $state = $memory; + } + + return true; + } +} diff --git a/administrator/components/com_finder/helpers/indexer/driver/postgresql.php b/administrator/components/com_finder/helpers/indexer/driver/postgresql.php new file mode 100644 index 0000000..114bdba --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/driver/postgresql.php @@ -0,0 +1,634 @@ +mark('beforeIndexing') : null; + $db = JFactory::getDbo(); + $nd = $db->getNullDate(); + + // Check if the item is in the database. + $query = $db->getQuery(true) + ->select($db->quoteName('link_id') . ', ' . $db->quoteName('md5sum')) + ->from($db->quoteName('#__finder_links')) + ->where($db->quoteName('url') . ' = ' . $db->quote($item->url)); + + // Load the item from the database. + $db->setQuery($query); + $link = $db->loadObject(); + + // Get the indexer state. + $state = static::getState(); + + // Get the signatures of the item. + $curSig = static::getSignature($item); + $oldSig = isset($link->md5sum) ? $link->md5sum : null; + + // Get the other item information. + $linkId = empty($link->link_id) ? null : $link->link_id; + $isNew = empty($link->link_id) ? true : false; + + // Check the signatures. If they match, the item is up to date. + if (!$isNew && $curSig == $oldSig) + { + return $linkId; + } + + /* + * If the link already exists, flush all the term maps for the item. + * Maps are stored in 16 tables so we need to iterate through and flush + * each table one at a time. + */ + if (!$isNew) + { + for ($i = 0; $i <= 15; $i++) + { + // Flush the maps for the link. + $query->clear() + ->delete($db->quoteName('#__finder_links_terms' . dechex($i))) + ->where($db->quoteName('link_id') . ' = ' . (int) $linkId); + $db->setQuery($query); + $db->execute(); + } + + // Remove the taxonomy maps. + FinderIndexerTaxonomy::removeMaps($linkId); + } + + // Mark afterUnmapping in the profiler. + static::$profiler ? static::$profiler->mark('afterUnmapping') : null; + + // Perform cleanup on the item data. + $item->publish_start_date = (int) $item->publish_start_date != 0 ? $item->publish_start_date : $nd; + $item->publish_end_date = (int) $item->publish_end_date != 0 ? $item->publish_end_date : $nd; + $item->start_date = (int) $item->start_date != 0 ? $item->start_date : $nd; + $item->end_date = (int) $item->end_date != 0 ? $item->end_date : $nd; + + // Prepare the item description. + $item->description = FinderIndexerHelper::parse($item->summary); + + /* + * Now, we need to enter the item into the links table. If the item + * already exists in the database, we need to use an UPDATE query. + * Otherwise, we need to use an INSERT to get the link id back. + */ + + if ($isNew) + { + $columnsArray = array( + $db->quoteName('url'), $db->quoteName('route'), $db->quoteName('title'), $db->quoteName('description'), + $db->quoteName('indexdate'), $db->quoteName('published'), $db->quoteName('state'), $db->quoteName('access'), + $db->quoteName('language'), $db->quoteName('type_id'), $db->quoteName('object'), $db->quoteName('publish_start_date'), + $db->quoteName('publish_end_date'), $db->quoteName('start_date'), $db->quoteName('end_date'), $db->quoteName('list_price'), + $db->quoteName('sale_price') + ); + + // Insert the link. + $query->clear() + ->insert($db->quoteName('#__finder_links')) + ->columns($columnsArray) + ->values( + $db->quote($item->url) . ', ' + . $db->quote($item->route) . ', ' + . $db->quote($item->title) . ', ' + . $db->quote($item->description) . ', ' + . $query->currentTimestamp() . ', ' + . '1, ' + . (int) $item->state . ', ' + . (int) $item->access . ', ' + . $db->quote($item->language) . ', ' + . (int) $item->type_id . ', ' + . $db->quote(serialize($item)) . ', ' + . $db->quote($item->publish_start_date) . ', ' + . $db->quote($item->publish_end_date) . ', ' + . $db->quote($item->start_date) . ', ' + . $db->quote($item->end_date) . ', ' + . (double) ($item->list_price ? $item->list_price : 0) . ', ' + . (double) ($item->sale_price ? $item->sale_price : 0) + ); + $db->setQuery($query); + $db->execute(); + + // Get the link id. + $linkId = (int) $db->insertid(); + } + else + { + // Update the link. + $query->clear() + ->update($db->quoteName('#__finder_links')) + ->set($db->quoteName('route') . ' = ' . $db->quote($item->route)) + ->set($db->quoteName('title') . ' = ' . $db->quote($item->title)) + ->set($db->quoteName('description') . ' = ' . $db->quote($item->description)) + ->set($db->quoteName('indexdate') . ' = ' . $query->currentTimestamp()) + ->set($db->quoteName('state') . ' = ' . (int) $item->state) + ->set($db->quoteName('access') . ' = ' . (int) $item->access) + ->set($db->quoteName('language') . ' = ' . $db->quote($item->language)) + ->set($db->quoteName('type_id') . ' = ' . (int) $item->type_id) + ->set($db->quoteName('object') . ' = ' . $db->quote(serialize($item))) + ->set($db->quoteName('publish_start_date') . ' = ' . $db->quote($item->publish_start_date)) + ->set($db->quoteName('publish_end_date') . ' = ' . $db->quote($item->publish_end_date)) + ->set($db->quoteName('start_date') . ' = ' . $db->quote($item->start_date)) + ->set($db->quoteName('end_date') . ' = ' . $db->quote($item->end_date)) + ->set($db->quoteName('list_price') . ' = ' . (double) ($item->list_price ? $item->list_price : 0)) + ->set($db->quoteName('sale_price') . ' = ' . (double) ($item->sale_price ? $item->sale_price : 0)) + ->where('link_id = ' . (int) $linkId); + $db->setQuery($query); + $db->execute(); + } + + // Set up the variables we will need during processing. + $count = 0; + + // Mark afterLinking in the profiler. + static::$profiler ? static::$profiler->mark('afterLinking') : null; + + // Truncate the tokens tables. + $db->truncateTable('#__finder_tokens'); + + // Truncate the tokens aggregate table. + $db->truncateTable('#__finder_tokens_aggregate'); + + /* + * Process the item's content. The items can customize their + * processing instructions to define extra properties to process + * or rearrange how properties are weighted. + */ + foreach ($item->getInstructions() as $group => $properties) + { + // Iterate through the properties of the group. + foreach ($properties as $property) + { + // Check if the property exists in the item. + if (empty($item->$property)) + { + continue; + } + + // Tokenize the property. + if (is_array($item->$property)) + { + // Tokenize an array of content and add it to the database. + foreach ($item->$property as $ip) + { + /* + * If the group is path, we need to a few extra processing + * steps to strip the extension and convert slashes and dashes + * to spaces. + */ + if ($group === static::PATH_CONTEXT) + { + $ip = JFile::stripExt($ip); + $ip = str_replace('/', ' ', $ip); + $ip = str_replace('-', ' ', $ip); + } + + // Tokenize a string of content and add it to the database. + $count += $this->tokenizeToDB($ip, $group, $item->language, $format); + + // Check if we're approaching the memory limit of the token table. + if ($count > static::$state->options->get('memory_table_limit', 30000)) + { + $this->toggleTables(false); + } + } + } + else + { + /* + * If the group is path, we need to a few extra processing + * steps to strip the extension and convert slashes and dashes + * to spaces. + */ + if ($group === static::PATH_CONTEXT) + { + $item->$property = JFile::stripExt($item->$property); + $item->$property = str_replace('/', ' ', $item->$property); + $item->$property = str_replace('-', ' ', $item->$property); + } + + // Tokenize a string of content and add it to the database. + $count += $this->tokenizeToDB($item->$property, $group, $item->language, $format); + + // Check if we're approaching the memory limit of the token table. + if ($count > static::$state->options->get('memory_table_limit', 30000)) + { + $this->toggleTables(false); + } + } + } + } + + /* + * Process the item's taxonomy. The items can customize their + * taxonomy mappings to define extra properties to map. + */ + foreach ($item->getTaxonomy() as $branch => $nodes) + { + // Iterate through the nodes and map them to the branch. + foreach ($nodes as $node) + { + // Add the node to the tree. + $nodeId = FinderIndexerTaxonomy::addNode($branch, $node->title, $node->state, $node->access); + + // Add the link => node map. + FinderIndexerTaxonomy::addMap($linkId, $nodeId); + + // Tokenize the node title and add them to the database. + $count += $this->tokenizeToDB($node->title, static::META_CONTEXT, $item->language, $format); + } + } + + // Mark afterProcessing in the profiler. + static::$profiler ? static::$profiler->mark('afterProcessing') : null; + + /* + * At this point, all of the item's content has been parsed, tokenized + * and inserted into the #__finder_tokens table. Now, we need to + * aggregate all the data into that table into a more usable form. The + * aggregated data will be inserted into #__finder_tokens_aggregate + * table. + */ + $query = 'INSERT INTO ' . $db->quoteName('#__finder_tokens_aggregate') . + ' (' . $db->quoteName('term_id') . + ', ' . $db->quoteName('term') . + ', ' . $db->quoteName('stem') . + ', ' . $db->quoteName('common') . + ', ' . $db->quoteName('phrase') . + ', ' . $db->quoteName('term_weight') . + ', ' . $db->quoteName('context') . + ', ' . $db->quoteName('context_weight') . + ', ' . $db->quoteName('language') . ')' . + ' SELECT' . + ' t.term_id, t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context,' . + ' ROUND( t1.weight * COUNT( t2.term ) * %F, 8 ) AS context_weight, t1.language' . + ' FROM (' . + ' SELECT DISTINCT t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, t1.language' . + ' FROM ' . $db->quoteName('#__finder_tokens') . ' AS t1' . + ' WHERE t1.context = %d' . + ' ) AS t1' . + ' JOIN ' . $db->quoteName('#__finder_tokens') . ' AS t2 ON t2.term = t1.term' . + ' LEFT JOIN ' . $db->quoteName('#__finder_terms') . ' AS t ON t.term = t1.term' . + ' WHERE t2.context = %d' . + ' GROUP BY t1.term, t.term_id, t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, t1.language' . + ' ORDER BY t1.term DESC'; + + // Iterate through the contexts and aggregate the tokens per context. + foreach ($state->weights as $context => $multiplier) + { + // Run the query to aggregate the tokens for this context.. + $db->setQuery(sprintf($query, $multiplier, $context, $context)); + $db->execute(); + } + + // Mark afterAggregating in the profiler. + static::$profiler ? static::$profiler->mark('afterAggregating') : null; + + /* + * When we pulled down all of the aggregate data, we did a LEFT JOIN + * over the terms table to try to find all the term ids that + * already exist for our tokens. If any of the rows in the aggregate + * table have a term of 0, then no term record exists for that + * term so we need to add it to the terms table. + */ + /* Emulation of IGNORE INTO behaviour */ + $db->setQuery( + ' SELECT ta.term' . + ' FROM ' . $db->quoteName('#__finder_tokens_aggregate') . ' AS ta' . + ' WHERE ta.term_id = 0' + ); + if ($db->loadRow() == null) + { + $db->setQuery( + 'INSERT INTO ' . $db->quoteName('#__finder_terms') . + ' (' . $db->quoteName('term') . + ', ' . $db->quoteName('stem') . + ', ' . $db->quoteName('common') . + ', ' . $db->quoteName('phrase') . + ', ' . $db->quoteName('weight') . + ', ' . $db->quoteName('soundex') . + ', ' . $db->quoteName('language') . ')' . + ' SELECT ta.term, ta.stem, ta.common, ta.phrase, ta.term_weight, SOUNDEX(ta.term), ta.language' . + ' FROM ' . $db->quoteName('#__finder_tokens_aggregate') . ' AS ta' . + ' WHERE ta.term_id = 0' . + ' GROUP BY ta.term, ta.stem, ta.common, ta.phrase, ta.term_weight, SOUNDEX(ta.term), ta.language' + ); + $db->execute(); + } + + /* + * Now, we just inserted a bunch of new records into the terms table + * so we need to go back and update the aggregate table with all the + * new term ids. + */ + $query = $db->getQuery(true) + ->update($db->quoteName('#__finder_tokens_aggregate') . ' AS ta') + ->join('INNER', $db->quoteName('#__finder_terms') . ' AS t ON t.term = ta.term') + ->set('ta.term_id = t.term_id') + ->where('ta.term_id = 0'); + $db->setQuery($query); + $db->execute(); + + // Mark afterTerms in the profiler. + static::$profiler ? static::$profiler->mark('afterTerms') : null; + + /* + * After we've made sure that all of the terms are in the terms table + * and the aggregate table has the correct term ids, we need to update + * the links counter for each term by one. + */ + $query->clear() + ->update($db->quoteName('#__finder_terms') . ' AS t') + ->join('INNER', $db->quoteName('#__finder_tokens_aggregate') . ' AS ta ON ta.term_id = t.term_id') + ->set('t.' . $db->quoteName('links') . ' = t.links + 1'); + $db->setQuery($query); + $db->execute(); + + // Mark afterTerms in the profiler. + static::$profiler ? static::$profiler->mark('afterTerms') : null; + + /* + * Before we can insert all of the mapping rows, we have to figure out + * which mapping table the rows need to be inserted into. The mapping + * table for each term is based on the first character of the md5 of + * the first character of the term. In php, it would be expressed as + * substr(md5(substr($token, 0, 1)), 0, 1) + */ + $query->clear() + ->update($db->quoteName('#__finder_tokens_aggregate')) + ->set($db->quoteName('map_suffix') . ' = SUBSTR(MD5(SUBSTR(' . $db->quoteName('term') . ', 1, 1)), 1, 1)'); + $db->setQuery($query); + $db->execute(); + + /* + * At this point, the aggregate table contains a record for each + * term in each context. So, we're going to pull down all of that + * data while grouping the records by term and add all of the + * sub-totals together to arrive at the final total for each token for + * this link. Then, we insert all of that data into the appropriate + * mapping table. + */ + for ($i = 0; $i <= 15; $i++) + { + // Get the mapping table suffix. + $suffix = dechex($i); + + /* + * We have to run this query 16 times, one for each link => term + * mapping table. + */ + $db->setQuery( + 'INSERT INTO ' . $db->quoteName('#__finder_links_terms' . $suffix) . + ' (' . $db->quoteName('link_id') . + ', ' . $db->quoteName('term_id') . + ', ' . $db->quoteName('weight') . ')' . + ' SELECT ' . (int) $linkId . ', ' . $db->quoteName('term_id') . ',' . + ' ROUND(SUM(' . $db->quoteName('context_weight') . '), 8)' . + ' FROM ' . $db->quoteName('#__finder_tokens_aggregate') . + ' WHERE ' . $db->quoteName('map_suffix') . ' = ' . $db->quote($suffix) . + ' GROUP BY ' . $db->quoteName('term') . + ' ORDER BY ' . $db->quoteName('term') . ' DESC' + ); + $db->execute(); + } + + // Mark afterMapping in the profiler. + static::$profiler ? static::$profiler->mark('afterMapping') : null; + + // Update the signature. + $query->clear() + ->update($db->quoteName('#__finder_links')) + ->set($db->quoteName('md5sum') . ' = ' . $db->quote($curSig)) + ->where($db->quoteName('link_id') . ' = ' . $db->quote($linkId)); + $db->setQuery($query); + $db->execute(); + + // Mark afterSigning in the profiler. + static::$profiler ? static::$profiler->mark('afterSigning') : null; + + // Truncate the tokens tables. + $db->truncateTable('#__finder_tokens'); + + // Truncate the tokens aggregate table. + $db->truncateTable('#__finder_tokens_aggregate'); + + // Toggle the token tables back to memory tables. + $this->toggleTables(true); + + // Mark afterTruncating in the profiler. + static::$profiler ? static::$profiler->mark('afterTruncating') : null; + + return $linkId; + } + + /** + * Method to remove a link from the index. + * + * @param integer $linkId The id of the link. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + public function remove($linkId) + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + // Update the link counts and remove the mapping records. + for ($i = 0; $i <= 15; $i++) + { + // Update the link counts for the terms. + $query->update($db->quoteName('#__finder_terms') . ' AS t') + ->join('INNER', $db->quoteName('#__finder_links_terms' . dechex($i)) . ' AS m ON m.term_id = t.term_id') + ->set('t.links = t.links - 1') + ->where('m.link_id = ' . $db->quote((int) $linkId)); + $db->setQuery($query); + $db->execute(); + + // Remove all records from the mapping tables. + $query->clear() + ->delete($db->quoteName('#__finder_links_terms' . dechex($i))) + ->where($db->quoteName('link_id') . ' = ' . (int) $linkId); + $db->setQuery($query); + $db->execute(); + } + + // Delete all orphaned terms. + $query->clear() + ->delete($db->quoteName('#__finder_terms')) + ->where($db->quoteName('links') . ' <= 0'); + $db->setQuery($query); + $db->execute(); + + // Delete the link from the index. + $query->clear() + ->delete($db->quoteName('#__finder_links')) + ->where($db->quoteName('link_id') . ' = ' . $db->quote((int) $linkId)); + $db->setQuery($query); + $db->execute(); + + // Remove the taxonomy maps. + FinderIndexerTaxonomy::removeMaps($linkId); + + // Remove the orphaned taxonomy nodes. + FinderIndexerTaxonomy::removeOrphanNodes(); + + return true; + } + + /** + * Method to optimize the index. We use this method to remove unused terms + * and any other optimizations that might be necessary. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + public function optimize() + { + // Get the database object. + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + // Delete all orphaned terms. + $query->delete($db->quoteName('#__finder_terms')) + ->where($db->quoteName('links') . ' <= 0'); + $db->setQuery($query); + $db->execute(); + + // Optimize the links table. + $db->setQuery('VACUUM ' . $db->quoteName('#__finder_links')); + $db->execute(); + $db->setQuery('REINDEX TABLE ' . $db->quoteName('#__finder_links')); + $db->execute(); + + for ($i = 0; $i <= 15; $i++) + { + // Optimize the terms mapping table. + $db->setQuery('VACUUM ' . $db->quoteName('#__finder_links_terms' . dechex($i))); + $db->execute(); + $db->setQuery('REINDEX TABLE ' . $db->quoteName('#__finder_links_terms' . dechex($i))); + $db->execute(); + } + + // Optimize the terms mapping table. + $db->setQuery('REINDEX TABLE ' . $db->quoteName('#__finder_links_terms')); + $db->execute(); + + // Remove the orphaned taxonomy nodes. + FinderIndexerTaxonomy::removeOrphanNodes(); + + // Optimize the taxonomy mapping table. + $db->setQuery('REINDEX TABLE ' . $db->quoteName('#__finder_taxonomy_map')); + $db->execute(); + + return true; + } + + /** + * Method to add a set of tokens to the database. + * + * @param mixed $tokens An array or single FinderIndexerToken object. + * @param mixed $context The context of the tokens. See context constants. [optional] + * + * @return integer The number of tokens inserted into the database. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function addTokensToDB($tokens, $context = '') + { + // Get the database object. + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + // Force tokens to an array. + $tokens = is_array($tokens) ? $tokens : array($tokens); + + // Count the number of token values. + $values = 0; + + // Insert the tokens into the database. + $query->insert($db->quoteName('#__finder_tokens')) + ->columns( + array( + $db->quoteName('term'), + $db->quoteName('stem'), + $db->quoteName('common'), + $db->quoteName('phrase'), + $db->quoteName('weight'), + $db->quoteName('context'), + $db->quoteName('language') + ) + ); + + // Iterate through the tokens to create SQL value sets. + foreach ($tokens as $token) + { + $query->values( + $db->quote($token->term) . ', ' + . $db->quote($token->stem) . ', ' + . (int) $token->common . ', ' + . (int) $token->phrase . ', ' + . (float) $token->weight . ', ' + . (int) $context . ', ' + . $db->quote($token->language) + ); + $values++; + } + $db->setQuery($query); + $db->execute(); + + return $values; + } + + /** + * Method to switch the token tables from Memory tables to MyISAM tables + * when they are close to running out of memory. + * + * @param boolean $memory Flag to control how they should be toggled. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function toggleTables($memory) + { + return true; + } +} diff --git a/administrator/components/com_finder/helpers/indexer/driver/sqlsrv.php b/administrator/components/com_finder/helpers/indexer/driver/sqlsrv.php new file mode 100644 index 0000000..56e80e6 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/driver/sqlsrv.php @@ -0,0 +1,630 @@ +mark('beforeIndexing') : null; + $db = JFactory::getDbo(); + $nd = $db->getNullDate(); + + // Check if the item is in the database. + $query = $db->getQuery(true) + ->select($db->quoteName('link_id') . ', ' . $db->quoteName('md5sum')) + ->from($db->quoteName('#__finder_links')) + ->where($db->quoteName('url') . ' = ' . $db->quote($item->url)); + + // Load the item from the database. + $db->setQuery($query); + $link = $db->loadObject(); + + // Get the indexer state. + $state = static::getState(); + + // Get the signatures of the item. + $curSig = static::getSignature($item); + $oldSig = isset($link->md5sum) ? $link->md5sum : null; + + // Get the other item information. + $linkId = empty($link->link_id) ? null : $link->link_id; + $isNew = empty($link->link_id) ? true : false; + + // Check the signatures. If they match, the item is up to date. + if (!$isNew && $curSig == $oldSig) + { + return $linkId; + } + + /* + * If the link already exists, flush all the term maps for the item. + * Maps are stored in 16 tables so we need to iterate through and flush + * each table one at a time. + */ + if (!$isNew) + { + for ($i = 0; $i <= 15; $i++) + { + // Flush the maps for the link. + $query->clear() + ->delete($db->quoteName('#__finder_links_terms' . dechex($i))) + ->where($db->quoteName('link_id') . ' = ' . (int) $linkId); + $db->setQuery($query); + $db->execute(); + } + + // Remove the taxonomy maps. + FinderIndexerTaxonomy::removeMaps($linkId); + } + + // Mark afterUnmapping in the profiler. + static::$profiler ? static::$profiler->mark('afterUnmapping') : null; + + // Perform cleanup on the item data. + $item->publish_start_date = (int) $item->publish_start_date != 0 ? $item->publish_start_date : $nd; + $item->publish_end_date = (int) $item->publish_end_date != 0 ? $item->publish_end_date : $nd; + $item->start_date = (int) $item->start_date != 0 ? $item->start_date : $nd; + $item->end_date = (int) $item->end_date != 0 ? $item->end_date : $nd; + + // Prepare the item description. + $item->description = FinderIndexerHelper::parse($item->summary); + + /* + * Now, we need to enter the item into the links table. If the item + * already exists in the database, we need to use an UPDATE query. + * Otherwise, we need to use an INSERT to get the link id back. + */ + + if ($isNew) + { + $columnsArray = array( + $db->quoteName('url'), $db->quoteName('route'), $db->quoteName('title'), $db->quoteName('description'), + $db->quoteName('indexdate'), $db->quoteName('published'), $db->quoteName('state'), $db->quoteName('access'), + $db->quoteName('language'), $db->quoteName('type_id'), $db->quoteName('object'), $db->quoteName('publish_start_date'), + $db->quoteName('publish_end_date'), $db->quoteName('start_date'), $db->quoteName('end_date'), $db->quoteName('list_price'), + $db->quoteName('sale_price') + ); + + // Insert the link. + $query->clear() + ->insert($db->quoteName('#__finder_links')) + ->columns($columnsArray) + ->values( + $db->quote($item->url) . ', ' + . $db->quote($item->route) . ', ' + . $db->quote($item->title) . ', ' + . $db->quote($item->description) . ', ' + . $query->currentTimestamp() . ', ' + . '1, ' + . (int) $item->state . ', ' + . (int) $item->access . ', ' + . $db->quote($item->language) . ', ' + . (int) $item->type_id . ', ' + . $db->quote(serialize($item)) . ', ' + . $db->quote($item->publish_start_date) . ', ' + . $db->quote($item->publish_end_date) . ', ' + . $db->quote($item->start_date) . ', ' + . $db->quote($item->end_date) . ', ' + . (double) ($item->list_price ? $item->list_price : 0) . ', ' + . (double) ($item->sale_price ? $item->sale_price : 0) + ); + $db->setQuery($query); + $db->execute(); + + // Get the link id. + $linkId = (int) $db->insertid(); + } + else + { + // Update the link. + $query->clear() + ->update($db->quoteName('#__finder_links')) + ->set($db->quoteName('route') . ' = ' . $db->quote($item->route)) + ->set($db->quoteName('title') . ' = ' . $db->quote($item->title)) + ->set($db->quoteName('description') . ' = ' . $db->quote($item->description)) + ->set($db->quoteName('indexdate') . ' = ' . $query->currentTimestamp()) + ->set($db->quoteName('state') . ' = ' . (int) $item->state) + ->set($db->quoteName('access') . ' = ' . (int) $item->access) + ->set($db->quoteName('language') . ' = ' . $db->quote($item->language)) + ->set($db->quoteName('type_id') . ' = ' . (int) $item->type_id) + ->set($db->quoteName('object') . ' = ' . $db->quote(serialize($item))) + ->set($db->quoteName('publish_start_date') . ' = ' . $db->quote($item->publish_start_date)) + ->set($db->quoteName('publish_end_date') . ' = ' . $db->quote($item->publish_end_date)) + ->set($db->quoteName('start_date') . ' = ' . $db->quote($item->start_date)) + ->set($db->quoteName('end_date') . ' = ' . $db->quote($item->end_date)) + ->set($db->quoteName('list_price') . ' = ' . (double) ($item->list_price ? $item->list_price : 0)) + ->set($db->quoteName('sale_price') . ' = ' . (double) ($item->sale_price ? $item->sale_price : 0)) + ->where('link_id = ' . (int) $linkId); + $db->setQuery($query); + $db->execute(); + } + + // Set up the variables we will need during processing. + $count = 0; + + // Mark afterLinking in the profiler. + static::$profiler ? static::$profiler->mark('afterLinking') : null; + + // Truncate the tokens tables. + $db->truncateTable('#__finder_tokens'); + + // Truncate the tokens aggregate table. + $db->truncateTable('#__finder_tokens_aggregate'); + + /* + * Process the item's content. The items can customize their + * processing instructions to define extra properties to process + * or rearrange how properties are weighted. + */ + foreach ($item->getInstructions() as $group => $properties) + { + // Iterate through the properties of the group. + foreach ($properties as $property) + { + // Check if the property exists in the item. + if (empty($item->$property)) + { + continue; + } + + // Tokenize the property. + if (is_array($item->$property)) + { + // Tokenize an array of content and add it to the database. + foreach ($item->$property as $ip) + { + /* + * If the group is path, we need to a few extra processing + * steps to strip the extension and convert slashes and dashes + * to spaces. + */ + if ($group === static::PATH_CONTEXT) + { + $ip = JFile::stripExt($ip); + $ip = str_replace('/', ' ', $ip); + $ip = str_replace('-', ' ', $ip); + } + + // Tokenize a string of content and add it to the database. + $count += $this->tokenizeToDB($ip, $group, $item->language, $format); + + // Check if we're approaching the memory limit of the token table. + if ($count > static::$state->options->get('memory_table_limit', 30000)) + { + $this->toggleTables(false); + } + } + } + else + { + /* + * If the group is path, we need to a few extra processing + * steps to strip the extension and convert slashes and dashes + * to spaces. + */ + if ($group === static::PATH_CONTEXT) + { + $item->$property = JFile::stripExt($item->$property); + $item->$property = str_replace('/', ' ', $item->$property); + $item->$property = str_replace('-', ' ', $item->$property); + } + + // Tokenize a string of content and add it to the database. + $count += $this->tokenizeToDB($item->$property, $group, $item->language, $format); + + // Check if we're approaching the memory limit of the token table. + if ($count > static::$state->options->get('memory_table_limit', 30000)) + { + $this->toggleTables(false); + } + } + } + } + + /* + * Process the item's taxonomy. The items can customize their + * taxonomy mappings to define extra properties to map. + */ + foreach ($item->getTaxonomy() as $branch => $nodes) + { + // Iterate through the nodes and map them to the branch. + foreach ($nodes as $node) + { + // Add the node to the tree. + $nodeId = FinderIndexerTaxonomy::addNode($branch, $node->title, $node->state, $node->access); + + // Add the link => node map. + FinderIndexerTaxonomy::addMap($linkId, $nodeId); + + // Tokenize the node title and add them to the database. + $count += $this->tokenizeToDB($node->title, static::META_CONTEXT, $item->language, $format); + } + } + + // Mark afterProcessing in the profiler. + static::$profiler ? static::$profiler->mark('afterProcessing') : null; + + /* + * At this point, all of the item's content has been parsed, tokenized + * and inserted into the #__finder_tokens table. Now, we need to + * aggregate all the data into that table into a more usable form. The + * aggregated data will be inserted into #__finder_tokens_aggregate + * table. + */ + $query = 'INSERT INTO ' . $db->quoteName('#__finder_tokens_aggregate') . + ' (' . $db->quoteName('term_id') . + ', ' . $db->quoteName('term') . + ', ' . $db->quoteName('stem') . + ', ' . $db->quoteName('common') . + ', ' . $db->quoteName('phrase') . + ', ' . $db->quoteName('term_weight') . + ', ' . $db->quoteName('context') . + ', ' . $db->quoteName('context_weight') . + ', ' . $db->quoteName('language') . ')' . + ' SELECT' . + ' t.term_id, t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context,' . + ' ROUND( t1.weight * COUNT( t2.term ) * %F, 8 ) AS context_weight, t1.language' . + ' FROM (' . + ' SELECT DISTINCT t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, t1.language' . + ' FROM ' . $db->quoteName('#__finder_tokens') . ' AS t1' . + ' WHERE t1.context = %d' . + ' ) AS t1' . + ' JOIN ' . $db->quoteName('#__finder_tokens') . ' AS t2 ON t2.term = t1.term' . + ' LEFT JOIN ' . $db->quoteName('#__finder_terms') . ' AS t ON t.term = t1.term' . + ' WHERE t2.context = %d' . + ' GROUP BY t1.term, t.term_id, t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, t1.language' . + ' ORDER BY t1.term DESC'; + + // Iterate through the contexts and aggregate the tokens per context. + foreach ($state->weights as $context => $multiplier) + { + // Run the query to aggregate the tokens for this context.. + $db->setQuery(sprintf($query, $multiplier, $context, $context)); + $db->execute(); + } + + // Mark afterAggregating in the profiler. + static::$profiler ? static::$profiler->mark('afterAggregating') : null; + + /* + * When we pulled down all of the aggregate data, we did a LEFT JOIN + * over the terms table to try to find all the term ids that + * already exist for our tokens. If any of the rows in the aggregate + * table have a term of 0, then no term record exists for that + * term so we need to add it to the terms table. + */ + $db->setQuery( + 'INSERT INTO ' . $db->quoteName('#__finder_terms') . + ' (' . $db->quoteName('term') . + ', ' . $db->quoteName('stem') . + ', ' . $db->quoteName('common') . + ', ' . $db->quoteName('phrase') . + ', ' . $db->quoteName('weight') . + ', ' . $db->quoteName('soundex') . ')' . + ' SELECT ta.term, ta.stem, ta.common, ta.phrase, ta.term_weight, SOUNDEX(ta.term)' . + ' FROM ' . $db->quoteName('#__finder_tokens_aggregate') . ' AS ta' . + ' WHERE ta.term_id IS NULL' . + ' GROUP BY ta.term, ta.stem, ta.common, ta.phrase, ta.term_weight' + ); + $db->execute(); + + /* + * Now, we just inserted a bunch of new records into the terms table + * so we need to go back and update the aggregate table with all the + * new term ids. + */ + $query = $db->getQuery(true) + ->update('ta') + ->set('ta.term_id = t.term_id from #__finder_tokens_aggregate AS ta INNER JOIN #__finder_terms AS t ON t.term = ta.term') + ->where('ta.term_id IS NULL'); + $db->setQuery($query); + $db->execute(); + + // Mark afterTerms in the profiler. + static::$profiler ? static::$profiler->mark('afterTerms') : null; + + /* + * After we've made sure that all of the terms are in the terms table + * and the aggregate table has the correct term ids, we need to update + * the links counter for each term by one. + */ + $query->clear() + ->update('t') + ->set('t.links = t.links + 1 FROM #__finder_terms AS t INNER JOIN #__finder_tokens_aggregate AS ta ON ta.term_id = t.term_id'); + $db->setQuery($query); + $db->execute(); + + // Mark afterTerms in the profiler. + static::$profiler ? static::$profiler->mark('afterTerms') : null; + + /* + * Before we can insert all of the mapping rows, we have to figure out + * which mapping table the rows need to be inserted into. The mapping + * table for each term is based on the first character of the md5 of + * the first character of the term. In php, it would be expressed as + * substr(md5(substr($token, 0, 1)), 0, 1) + */ + $query->clear() + ->update($db->quoteName('#__finder_tokens_aggregate')) + ->set($db->quoteName('map_suffix') . " = SUBSTRING(HASHBYTES('MD5', SUBSTRING(" . $db->quoteName('term') . ', 1, 1)), 1, 1)'); + $db->setQuery($query); + $db->execute(); + + /* + * At this point, the aggregate table contains a record for each + * term in each context. So, we're going to pull down all of that + * data while grouping the records by term and add all of the + * sub-totals together to arrive at the final total for each token for + * this link. Then, we insert all of that data into the appropriate + * mapping table. + */ + for ($i = 0; $i <= 15; $i++) + { + // Get the mapping table suffix. + $suffix = dechex($i); + + /* + * We have to run this query 16 times, one for each link => term + * mapping table. + */ + $db->setQuery( + 'INSERT INTO ' . $db->quoteName('#__finder_links_terms' . $suffix) . + ' (' . $db->quoteName('link_id') . + ', ' . $db->quoteName('term_id') . + ', ' . $db->quoteName('weight') . ')' . + ' SELECT ' . (int) $linkId . ', ' . $db->quoteName('term_id') . ',' . + ' ROUND(SUM(' . $db->quoteName('context_weight') . '), 8)' . + ' FROM ' . $db->quoteName('#__finder_tokens_aggregate') . + ' WHERE ' . $db->quoteName('map_suffix') . ' = ' . $db->quote($suffix) . + ' GROUP BY term, term_id' . + ' ORDER BY ' . $db->quoteName('term') . ' DESC' + ); + $db->execute(); + } + + // Mark afterMapping in the profiler. + static::$profiler ? static::$profiler->mark('afterMapping') : null; + + // Update the signature. + $query->clear() + ->update($db->quoteName('#__finder_links')) + ->set($db->quoteName('md5sum') . ' = ' . $db->quote($curSig)) + ->where($db->quoteName('link_id') . ' = ' . $db->quote($linkId)); + $db->setQuery($query); + $db->execute(); + + // Mark afterSigning in the profiler. + static::$profiler ? static::$profiler->mark('afterSigning') : null; + + // Truncate the tokens tables. + $db->truncateTable('#__finder_tokens'); + + // Truncate the tokens aggregate table. + $db->truncateTable('#__finder_tokens_aggregate'); + + // Toggle the token tables back to memory tables. + $this->toggleTables(true); + + // Mark afterTruncating in the profiler. + static::$profiler ? static::$profiler->mark('afterTruncating') : null; + + return $linkId; + } + + /** + * Method to remove a link from the index. + * + * @param integer $linkId The id of the link. + * + * @return boolean True on success. + * + * @since 3.1 + * @throws Exception on database error. + */ + public function remove($linkId) + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + // Update the link counts and remove the mapping records. + for ($i = 0; $i <= 15; $i++) + { + // Update the link counts for the terms. + $query->update('t') + ->set('t.links = t.links - 1 from #__finder_terms AS t INNER JOIN #__finder_links_terms' . dechex($i) . ' AS AS m ON m.term_id = t.term_id') + ->where('m.link_id = ' . $db->quote((int) $linkId)); + $db->setQuery($query); + $db->execute(); + + // Remove all records from the mapping tables. + $query->clear() + ->delete($db->quoteName('#__finder_links_terms' . dechex($i))) + ->where($db->quoteName('link_id') . ' = ' . (int) $linkId); + $db->setQuery($query); + $db->execute(); + } + + // Delete all orphaned terms. + $query->clear() + ->delete($db->quoteName('#__finder_terms')) + ->where($db->quoteName('links') . ' <= 0'); + $db->setQuery($query); + $db->execute(); + + // Delete the link from the index. + $query->clear() + ->delete($db->quoteName('#__finder_links')) + ->where($db->quoteName('link_id') . ' = ' . $db->quote((int) $linkId)); + $db->setQuery($query); + $db->execute(); + + // Remove the taxonomy maps. + FinderIndexerTaxonomy::removeMaps($linkId); + + // Remove the orphaned taxonomy nodes. + FinderIndexerTaxonomy::removeOrphanNodes(); + + return true; + } + + /** + * Method to optimize the index. We use this method to remove unused terms + * and any other optimizations that might be necessary. + * + * @return boolean True on success. + * + * @since 3.1 + * @throws Exception on database error. + */ + public function optimize() + { + // Get the database object. + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + // Delete all orphaned terms. + $query->delete($db->quoteName('#__finder_terms')) + ->where($db->quoteName('links') . ' <= 0'); + $db->setQuery($query); + $db->execute(); + + // Remove the orphaned taxonomy nodes. + FinderIndexerTaxonomy::removeOrphanNodes(); + + return true; + } + + /** + * Method to add a set of tokens to the database. + * + * @param mixed $tokens An array or single FinderIndexerToken object. + * @param mixed $context The context of the tokens. See context constants. [optional] + * + * @return integer The number of tokens inserted into the database. + * + * @since 3.1 + * @throws Exception on database error. + */ + protected function addTokensToDB($tokens, $context = '') + { + // Get the database object. + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + // Force tokens to an array. + $tokens = is_array($tokens) ? $tokens : array($tokens); + + // Count the number of token values. + $values = 0; + + // Set some variables to count the iterations + $totalTokens = count($tokens); + $remaining = $totalTokens; + $iterations = 0; + $loop = true; + + do + { + // Shift the token off the array + $token = array_shift($tokens); + + $query->values( + $db->quote($token->term) . ', ' + . $db->quote($token->stem) . ', ' + . (int) $token->common . ', ' + . (int) $token->phrase . ', ' + . (float) $token->weight . ', ' + . (int) $context . ', ' + . $db->quote($token->language) + ); + $values++; + $iterations++; + $remaining--; + + // Run the query if we've reached 1000 iterations or there are no tokens remaining + if ($iterations == 1000 || $remaining == 0) + { + // Insert the tokens into the database. + $query->insert($db->quoteName('#__finder_tokens')) + ->columns( + array( + $db->quoteName('term'), + $db->quoteName('stem'), + $db->quoteName('common'), + $db->quoteName('phrase'), + $db->quoteName('weight'), + $db->quoteName('context'), + $db->quoteName('language') + ) + ); + $db->setQuery($query); + $db->execute(); + + // Reset the query + $query->clear(); + } + + // If there's nothing remaining, we're done looping + if ($remaining == 0) + { + $loop = false; + } + } + while ($loop == true); + + return $values; + } + + /** + * Method to switch the token tables from Memory tables to MyISAM tables + * when they are close to running out of memory. + * + * @param boolean $memory Flag to control how they should be toggled. + * + * @return boolean True on success. + * + * @since 3.1 + * @throws Exception on database error. + */ + protected function toggleTables($memory) + { + return true; + } +} diff --git a/administrator/components/com_finder/helpers/indexer/helper.php b/administrator/components/com_finder/helpers/indexer/helper.php new file mode 100644 index 0000000..ff5f8d2 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/helper.php @@ -0,0 +1,506 @@ +parse($input); + } + + /** + * Method to tokenize a text string. + * + * @param string $input The input to tokenize. + * @param string $lang The language of the input. + * @param boolean $phrase Flag to indicate whether input could be a phrase. [optional] + * + * @return array An array of FinderIndexerToken objects. + * + * @since 2.5 + */ + public static function tokenize($input, $lang, $phrase = false) + { + static $cache; + $store = JString::strlen($input) < 128 ? md5($input . '::' . $lang . '::' . $phrase) : null; + + // Check if the string has been tokenized already. + if ($store && isset($cache[$store])) + { + return $cache[$store]; + } + + $tokens = array(); + $quotes = html_entity_decode('‘’'', ENT_QUOTES, 'UTF-8'); + + // Get the simple language key. + $lang = self::getPrimaryLanguage($lang); + + /* + * Parsing the string input into terms is a multi-step process. + * + * Regexes: + * 1. Remove everything except letters, numbers, quotes, apostrophe, plus, dash, period, and comma. + * 2. Remove plus, dash, period, and comma characters located before letter characters. + * 3. Remove plus, dash, period, and comma characters located after other characters. + * 4. Remove plus, period, and comma characters enclosed in alphabetical characters. Ungreedy. + * 5. Remove orphaned apostrophe, plus, dash, period, and comma characters. + * 6. Remove orphaned quote characters. + * 7. Replace the assorted single quotation marks with the ASCII standard single quotation. + * 8. Remove multiple space characters and replaces with a single space. + */ + $input = JString::strtolower($input); + $input = preg_replace('#[^\pL\pM\pN\p{Pi}\p{Pf}\'+-.,]+#mui', ' ', $input); + $input = preg_replace('#(^|\s)[+-.,]+([\pL\pM]+)#mui', ' $1', $input); + $input = preg_replace('#([\pL\pM\pN]+)[+-.,]+(\s|$)#mui', '$1 ', $input); + $input = preg_replace('#([\pL\pM]+)[+.,]+([\pL\pM]+)#muiU', '$1 $2', $input); + $input = preg_replace('#(^|\s)[\'+-.,]+(\s|$)#mui', ' ', $input); + $input = preg_replace('#(^|\s)[\p{Pi}\p{Pf}]+(\s|$)#mui', ' ', $input); + $input = preg_replace('#[' . $quotes . ']+#mui', '\'', $input); + $input = preg_replace('#\s+#mui', ' ', $input); + $input = JString::trim($input); + + // Explode the normalized string to get the terms. + $terms = explode(' ', $input); + + /* + * If we have Unicode support and are dealing with Chinese text, Chinese + * has to be handled specially because there are not necessarily any spaces + * between the "words". So, we have to test if the words belong to the Chinese + * character set and if so, explode them into single glyphs or "words". + */ + if ($lang === 'zh') + { + // Iterate through the terms and test if they contain Chinese. + for ($i = 0, $n = count($terms); $i < $n; $i++) + { + $charMatches = array(); + $charCount = preg_match_all('#[\p{Han}]#mui', $terms[$i], $charMatches); + + // Split apart any groups of Chinese characters. + for ($j = 0; $j < $charCount; $j++) + { + $tSplit = JString::str_ireplace($charMatches[0][$j], '', $terms[$i], false); + if (!empty($tSplit)) + { + $terms[$i] = $tSplit; + } + else + { + unset($terms[$i]); + } + + $terms[] = $charMatches[0][$j]; + } + } + + // Reset array keys. + $terms = array_values($terms); + } + + /* + * If we have to handle the input as a phrase, that means we don't + * tokenize the individual terms and we do not create the two and three + * term combinations. The phrase must contain more than one word! + */ + if ($phrase === true && count($terms) > 1) + { + // Create tokens from the phrase. + $tokens[] = new FinderIndexerToken($terms, $lang); + } + else + { + // Create tokens from the terms. + for ($i = 0, $n = count($terms); $i < $n; $i++) + { + $tokens[] = new FinderIndexerToken($terms[$i], $lang); + } + + // Create two and three word phrase tokens from the individual words. + for ($i = 0, $n = count($tokens); $i < $n; $i++) + { + // Setup the phrase positions. + $i2 = $i + 1; + $i3 = $i + 2; + + // Create the two word phrase. + if ($i2 < $n && isset($tokens[$i2])) + { + // Tokenize the two word phrase. + $token = new FinderIndexerToken(array($tokens[$i]->term, $tokens[$i2]->term), $lang, $lang === 'zh' ? '' : ' '); + $token->derived = true; + + // Add the token to the stack. + $tokens[] = $token; + } + + // Create the three word phrase. + if ($i3 < $n && isset($tokens[$i3])) + { + // Tokenize the three word phrase. + $token = new FinderIndexerToken(array($tokens[$i]->term, $tokens[$i2]->term, $tokens[$i3]->term), $lang, $lang === 'zh' ? '' : ' '); + $token->derived = true; + + // Add the token to the stack. + $tokens[] = $token; + } + } + } + + if ($store) + { + $cache[$store] = count($tokens) > 1 ? $tokens : array_shift($tokens); + return $cache[$store]; + } + else + { + return count($tokens) > 1 ? $tokens : array_shift($tokens); + } + } + + /** + * Method to get the base word of a token. This method uses the public + * {@link FinderIndexerHelper::$stemmer} object if it is set. If no stemmer is set, + * the original token is returned. + * + * @param string $token The token to stem. + * @param string $lang The language of the token. + * + * @return string The root token. + * + * @since 2.5 + */ + public static function stem($token, $lang) + { + // Trim apostrophes at either end of the token. + $token = JString::trim($token, '\''); + + // Trim everything after any apostrophe in the token. + if (($pos = JString::strpos($token, '\'')) !== false) + { + $token = JString::substr($token, 0, $pos); + } + + // Stem the token if we have a valid stemmer to use. + if (self::$stemmer instanceof FinderIndexerStemmer) + { + return self::$stemmer->stem($token, $lang); + } + else + { + return $token; + } + } + + /** + * Method to add a content type to the database. + * + * @param string $title The type of content. For example: PDF + * @param string $mime The mime type of the content. For example: PDF [optional] + * + * @return integer The id of the content type. + * + * @since 2.5 + * @throws Exception on database error. + */ + public static function addContentType($title, $mime = null) + { + static $types; + + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + // Check if the types are loaded. + if (empty($types)) + { + // Build the query to get the types. + $query->select('*') + ->from($db->quoteName('#__finder_types')); + + // Get the types. + $db->setQuery($query); + $types = $db->loadObjectList('title'); + } + + // Check if the type already exists. + if (isset($types[$title])) + { + return (int) $types[$title]->id; + } + + // Add the type. + $query->clear() + ->insert($db->quoteName('#__finder_types')) + ->columns(array($db->quoteName('title'), $db->quoteName('mime'))) + ->values($db->quote($title) . ', ' . $db->quote($mime)); + $db->setQuery($query); + $db->execute(); + + // Return the new id. + return (int) $db->insertid(); + } + + /** + * Method to check if a token is common in a language. + * + * @param string $token The token to test. + * @param string $lang The language to reference. + * + * @return boolean True if common, false otherwise. + * + * @since 2.5 + */ + public static function isCommon($token, $lang) + { + static $data; + + // Load the common tokens for the language if necessary. + if (!isset($data[$lang])) + { + $data[$lang] = self::getCommonWords($lang); + } + + // Check if the token is in the common array. + if (in_array($token, $data[$lang])) + { + return true; + } + else + { + return false; + } + } + + /** + * Method to get an array of common terms for a language. + * + * @param string $lang The language to use. + * + * @return array Array of common terms. + * + * @since 2.5 + * @throws Exception on database error. + */ + public static function getCommonWords($lang) + { + $db = JFactory::getDbo(); + + // Create the query to load all the common terms for the language. + $query = $db->getQuery(true) + ->select($db->quoteName('term')) + ->from($db->quoteName('#__finder_terms_common')) + ->where($db->quoteName('language') . ' = ' . $db->quote($lang)); + + // Load all of the common terms for the language. + $db->setQuery($query); + $results = $db->loadColumn(); + + return $results; + } + + /** + * Method to get the default language for the site. + * + * @return string The default language string. + * + * @since 2.5 + */ + public static function getDefaultLanguage() + { + static $lang; + + // We need to go to com_languages to get the site default language, it's the best we can guess. + if (empty($lang)) + { + $lang = JComponentHelper::getParams('com_languages')->get('site', 'en-GB'); + } + + return $lang; + } + + /** + * Method to parse a language/locale key and return a simple language string. + * + * @param string $lang The language/locale key. For example: en-GB + * + * @return string The simple language string. For example: en + * + * @since 2.5 + */ + public static function getPrimaryLanguage($lang) + { + static $data; + + // Only parse the identifier if necessary. + if (!isset($data[$lang])) + { + if (is_callable(array('Locale', 'getPrimaryLanguage'))) + { + // Get the language key using the Locale package. + $data[$lang] = Locale::getPrimaryLanguage($lang); + } + else + { + // Get the language key using string position. + $data[$lang] = JString::substr($lang, 0, JString::strpos($lang, '-')); + } + } + + return $data[$lang]; + } + + /** + * Method to get the path (SEF route) for a content item. + * + * @param string $url The non-SEF route to the content item. + * + * @return string The path for the content item. + * + * @since 2.5 + */ + public static function getContentPath($url) + { + static $router; + + // Only get the router once. + if (!($router instanceof JRouter)) + { + jimport('joomla.application.router'); + include_once JPATH_SITE . '/includes/application.php'; + + // Get and configure the site router. + $config = JFactory::getConfig(); + $router = JRouter::getInstance('site'); + $router->setMode($config->get('sef', 1)); + } + + // Build the relative route. + $uri = $router->build($url); + $route = $uri->toString(array('path', 'query', 'fragment')); + $route = str_replace(JUri::base(true) . '/', '', $route); + + return $route; + } + + /** + * Method to get extra data for a content before being indexed. This is how + * we add Comments, Tags, Labels, etc. that should be available to Finder. + * + * @param FinderIndexerResult &$item The item to index as an FinderIndexerResult object. + * + * @return boolean True on success, false on failure. + * + * @since 2.5 + * @throws Exception on database error. + */ + public static function getContentExtras(FinderIndexerResult &$item) + { + // Get the event dispatcher. + $dispatcher = JEventDispatcher::getInstance(); + + // Load the finder plugin group. + JPluginHelper::importPlugin('finder'); + + try + { + // Trigger the event. + $results = $dispatcher->trigger('onPrepareFinderContent', array(&$item)); + + // Check the returned results. This is for plugins that don't throw + // exceptions when they encounter serious errors. + if (in_array(false, $results)) + { + throw new Exception($dispatcher->getError(), 500); + } + } + catch (Exception $e) + { + // Handle a caught exception. + throw $e; + } + + return true; + } + + /** + * Method to process content text using the onContentPrepare event trigger. + * + * @param string $text The content to process. + * @param JRegistry $params The parameters object. [optional] + * + * @return string The processed content. + * + * @since 2.5 + */ + public static function prepareContent($text, $params = null) + { + static $loaded; + + // Get the dispatcher. + $dispatcher = JEventDispatcher::getInstance(); + + // Load the content plugins if necessary. + if (empty($loaded)) + { + JPluginHelper::importPlugin('content'); + $loaded = true; + } + + // Instantiate the parameter object if necessary. + if (!($params instanceof JRegistry)) + { + $registry = new JRegistry; + $registry->loadString($params); + $params = $registry; + } + + // Create a mock content object. + $content = JTable::getInstance('Content'); + $content->text = $text; + + // Fire the onContentPrepare event. + $dispatcher->trigger('onContentPrepare', array('com_finder.indexer', &$content, &$params, 0)); + + return $content->text; + } +} diff --git a/administrator/components/com_finder/helpers/indexer/index.html b/administrator/components/com_finder/helpers/indexer/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/helpers/indexer/indexer.php b/administrator/components/com_finder/helpers/indexer/indexer.php new file mode 100644 index 0000000..1972681 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/indexer.php @@ -0,0 +1,484 @@ +name; + + if ($format == 'mysqli') + { + $format = 'mysql'; + } + elseif ($format == 'sqlazure') + { + $format = 'sqlsrv'; + } + $path = __DIR__ . '/driver/' . $format . '.php'; + $class = 'FinderIndexerDriver' . ucfirst($format); + + // Check if a parser exists for the format. + if (file_exists($path)) + { + // Instantiate the parser. + include_once $path; + return new $class; + } + else + { + // Throw invalid format exception. + throw new RuntimeException(JText::sprintf('COM_FINDER_INDEXER_INVALID_DRIVER', $format)); + } + } + + /** + * Method to get the indexer state. + * + * @return object The indexer state object. + * + * @since 2.5 + */ + public static function getState() + { + // First, try to load from the internal state. + if (!empty(self::$state)) + { + return self::$state; + } + + // If we couldn't load from the internal state, try the session. + $session = JFactory::getSession(); + $data = $session->get('_finder.state', null); + + // If the state is empty, load the values for the first time. + if (empty($data)) + { + $data = new JObject; + + // Load the default configuration options. + $data->options = JComponentHelper::getParams('com_finder'); + + // Setup the weight lookup information. + $data->weights = array( + self::TITLE_CONTEXT => round($data->options->get('title_multiplier', 1.7), 2), + self::TEXT_CONTEXT => round($data->options->get('text_multiplier', 0.7), 2), + self::META_CONTEXT => round($data->options->get('meta_multiplier', 1.2), 2), + self::PATH_CONTEXT => round($data->options->get('path_multiplier', 2.0), 2), + self::MISC_CONTEXT => round($data->options->get('misc_multiplier', 0.3), 2) + ); + + // Set the current time as the start time. + $data->startTime = JFactory::getDate()->toSQL(); + + // Set the remaining default values. + $data->batchSize = (int) $data->options->get('batch_size', 50); + $data->batchOffset = 0; + $data->totalItems = 0; + $data->pluginState = array(); + } + + // Setup the profiler if debugging is enabled. + if (JFactory::getApplication()->getCfg('debug')) + { + self::$profiler = JProfiler::getInstance('FinderIndexer'); + } + + // Setup the stemmer. + if ($data->options->get('stem', 1) && $data->options->get('stemmer', 'porter_en')) + { + FinderIndexerHelper::$stemmer = FinderIndexerStemmer::getInstance($data->options->get('stemmer', 'porter_en')); + } + + // Set the state. + self::$state = $data; + + return self::$state; + } + + /** + * Method to set the indexer state. + * + * @param object $data A new indexer state object. + * + * @return boolean True on success, false on failure. + * + * @since 2.5 + */ + public static function setState($data) + { + // Check the state object. + if (empty($data) || !$data instanceof JObject) + { + return false; + } + + // Set the new internal state. + self::$state = $data; + + // Set the new session state. + $session = JFactory::getSession(); + $session->set('_finder.state', $data); + + return true; + } + + /** + * Method to reset the indexer state. + * + * @return void + * + * @since 2.5 + */ + public static function resetState() + { + // Reset the internal state to null. + self::$state = null; + + // Reset the session state to null. + $session = JFactory::getSession(); + $session->set('_finder.state', null); + } + + /** + * Method to index a content item. + * + * @param FinderIndexerResult $item The content item to index. + * @param string $format The format of the content. [optional] + * + * @return integer The ID of the record in the links table. + * + * @since 2.5 + * @throws Exception on database error. + */ + abstract public function index($item, $format = 'html'); + + /** + * Method to remove a link from the index. + * + * @param integer $linkId The id of the link. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + abstract public function remove($linkId); + + /** + * Method to optimize the index. We use this method to remove unused terms + * and any other optimizations that might be necessary. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + abstract public function optimize(); + + /** + * Method to get a content item's signature. + * + * @param object $item The content item to index. + * + * @return string The content item's signature. + * + * @since 2.5 + */ + protected static function getSignature($item) + { + // Get the indexer state. + $state = self::getState(); + + // Get the relevant configuration variables. + $config = array(); + $config[] = $state->weights; + $config[] = $state->options->get('stem', 1); + $config[] = $state->options->get('stemmer', 'porter_en'); + + return md5(serialize(array($item, $config))); + } + + /** + * Method to parse input, tokenize it, and then add it to the database. + * + * @param mixed $input String or resource to use as input. A resource + * input will automatically be chunked to conserve + * memory. Strings will be chunked if longer than + * 2K in size. + * @param integer $context The context of the input. See context constants. + * @param string $lang The language of the input. + * @param string $format The format of the input. + * + * @return integer The number of tokens extracted from the input. + * + * @since 2.5 + */ + protected function tokenizeToDB($input, $context, $lang, $format) + { + $count = 0; + $buffer = null; + + if (!empty($input)) + { + // If the input is a resource, batch the process out. + if (is_resource($input)) + { + // Batch the process out to avoid memory limits. + while (!feof($input)) + { + // Read into the buffer. + $buffer .= fread($input, 2048); + + /* + * If we haven't reached the end of the file, seek to the last + * space character and drop whatever is after that to make sure + * we didn't truncate a term while reading the input. + */ + if (!feof($input)) + { + // Find the last space character. + $ls = strrpos($buffer, ' '); + + // Adjust string based on the last space character. + if ($ls) + { + // Truncate the string to the last space character. + $string = substr($buffer, 0, $ls); + + // Adjust the buffer based on the last space for the next iteration and trim. + $buffer = JString::trim(substr($buffer, $ls)); + } + // No space character was found. + else + { + $string = $buffer; + } + } + // We've reached the end of the file, so parse whatever remains. + else + { + $string = $buffer; + } + + // Parse the input. + $string = FinderIndexerHelper::parse($string, $format); + + // Check the input. + if (empty($string)) + { + continue; + } + + // Tokenize the input. + $tokens = FinderIndexerHelper::tokenize($string, $lang); + + // Add the tokens to the database. + $count += $this->addTokensToDB($tokens, $context); + + // Check if we're approaching the memory limit of the token table. + if ($count > self::$state->options->get('memory_table_limit', 30000)) + { + self::toggleTables(false); + } + + unset($string); + unset($tokens); + } + } + // If the input is greater than 2K in size, it is more efficient to + // batch out the operation into smaller chunks of work. + elseif (strlen($input) > 2048) + { + $start = 0; + $end = strlen($input); + $chunk = 2048; + + /* + * As it turns out, the complex regular expressions we use for + * sanitizing input are not very efficient when given large + * strings. It is much faster to process lots of short strings. + */ + while ($start < $end) + { + // Setup the string. + $string = substr($input, $start, $chunk); + + // Find the last space character if we aren't at the end. + $ls = (($start + $chunk) < $end ? strrpos($string, ' ') : false); + + // Truncate to the last space character. + if ($ls !== false) + { + $string = substr($string, 0, $ls); + } + + // Adjust the start position for the next iteration. + $start += ($ls !== false ? ($ls + 1 - $chunk) + $chunk : $chunk); + + // Parse the input. + $string = FinderIndexerHelper::parse($string, $format); + + // Check the input. + if (empty($string)) + { + continue; + } + + // Tokenize the input. + $tokens = FinderIndexerHelper::tokenize($string, $lang); + + // Add the tokens to the database. + $count += $this->addTokensToDB($tokens, $context); + + // Check if we're approaching the memory limit of the token table. + if ($count > self::$state->options->get('memory_table_limit', 30000)) + { + self::toggleTables(false); + } + } + } + else + { + // Parse the input. + $input = FinderIndexerHelper::parse($input, $format); + + // Check the input. + if (empty($input)) + { + return $count; + } + + // Tokenize the input. + $tokens = FinderIndexerHelper::tokenize($input, $lang); + + // Add the tokens to the database. + $count = $this->addTokensToDB($tokens, $context); + } + } + + return $count; + } + + /** + * Method to add a set of tokens to the database. + * + * @param mixed $tokens An array or single FinderIndexerToken object. + * @param mixed $context The context of the tokens. See context constants. [optional] + * + * @return integer The number of tokens inserted into the database. + * + * @since 2.5 + * @throws Exception on database error. + */ + abstract protected function addTokensToDB($tokens, $context = ''); + + /** + * Method to switch the token tables from Memory tables to MyISAM tables + * when they are close to running out of memory. + * + * @param boolean $memory Flag to control how they should be toggled. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + abstract protected function toggleTables($memory); +} diff --git a/administrator/components/com_finder/helpers/indexer/parser.php b/administrator/components/com_finder/helpers/indexer/parser.php new file mode 100644 index 0000000..0f87e29 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/parser.php @@ -0,0 +1,132 @@ +clean($format, 'cmd'); + $path = __DIR__ . '/parser/' . $format . '.php'; + $class = 'FinderIndexerParser' . ucfirst($format); + + // Check if a parser exists for the format. + if (file_exists($path)) + { + // Instantiate the parser. + include_once $path; + $instances[$format] = new $class; + } + else + { + // Throw invalid format exception. + throw new Exception(JText::sprintf('COM_FINDER_INDEXER_INVALID_PARSER', $format)); + } + + return $instances[$format]; + } + + /** + * Method to parse input and extract the plain text. Because this method is + * called from both inside and outside the indexer, it needs to be able to + * batch out its parsing functionality to deal with the inefficiencies of + * regular expressions. We will parse recursively in 2KB chunks. + * + * @param string $input The input to parse. + * + * @return string The plain text input. + * + * @since 2.5 + */ + public function parse($input) + { + $return = null; + + // Parse the input in batches if bigger than 2KB. + if (strlen($input) > 2048) + { + $start = 0; + $end = strlen($input); + $chunk = 2048; + + while ($start < $end) + { + // Setup the string. + $string = substr($input, $start, $chunk); + + // Find the last space character if we aren't at the end. + $ls = (($start + $chunk) < $end ? strrpos($string, ' ') : false); + + // Truncate to the last space character. + if ($ls !== false) + { + $string = substr($string, 0, $ls); + } + + // Adjust the start position for the next iteration. + $start += ($ls !== false ? ($ls + 1 - $chunk) + $chunk : $chunk); + + // Parse the chunk. + $return .= $this->process($string); + } + } + // The input is less than 2KB so we can parse it efficiently. + else + { + // Parse the chunk. + $return .= $this->process($input); + } + + return $return; + } + + /** + * Method to process input and extract the plain text. + * + * @param string $input The input to process. + * + * @return string The plain text input. + * + * @since 2.5 + */ + abstract protected function process($input); +} diff --git a/administrator/components/com_finder/helpers/indexer/parser/html.php b/administrator/components/com_finder/helpers/indexer/parser/html.php new file mode 100644 index 0000000..e9830f3 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/parser/html.php @@ -0,0 +1,52 @@ +]*>.*?#si', ' ', $input); + + // Deal with spacing issues in the input. + $input = str_replace('>', '> ', $input); + $input = str_replace(array(' ', ' '), ' ', $input); + $input = trim(preg_replace('#\s+#u', ' ', $input)); + + // Strip the tags from the input and decode entities. + $input = strip_tags($input); + $input = html_entity_decode($input, ENT_QUOTES, 'UTF-8'); + $input = trim(preg_replace('#\s+#u', ' ', $input)); + + return $input; + } +} diff --git a/administrator/components/com_finder/helpers/indexer/parser/index.html b/administrator/components/com_finder/helpers/indexer/parser/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/parser/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/helpers/indexer/parser/rtf.php b/administrator/components/com_finder/helpers/indexer/parser/rtf.php new file mode 100644 index 0000000..7563c19 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/parser/rtf.php @@ -0,0 +1,44 @@ +input = isset($options['input']) ? $options['input'] : null; + + // Get the empty query setting. + $this->empty = isset($options['empty']) ? (bool) $options['empty'] : false; + + // Get the input language. + $this->language = !empty($options['language']) ? $options['language'] : FinderIndexerHelper::getDefaultLanguage(); + $this->language = FinderIndexerHelper::getPrimaryLanguage($this->language); + + // Get the matching mode. + $this->mode = 'AND'; + + // Initialize the temporary date storage. + $this->dates = new JRegistry; + + // Populate the temporary date storage. + if (isset($options['date1']) && !empty($options['date1'])) + { + $this->dates->set('date1', $options['date1']); + } + if (isset($options['date2']) && !empty($options['date1'])) + { + $this->dates->set('date2', $options['date2']); + } + if (isset($options['when1']) && !empty($options['date1'])) + { + $this->dates->set('when1', $options['when1']); + } + if (isset($options['when2']) && !empty($options['date1'])) + { + $this->dates->set('when2', $options['when2']); + } + + // Process the static taxonomy filters. + if (isset($options['filter']) && !empty($options['filter'])) + { + $this->processStaticTaxonomy($options['filter']); + } + + // Process the dynamic taxonomy filters. + if (isset($options['filters']) && !empty($options['filters'])) + { + $this->processDynamicTaxonomy($options['filters']); + } + + // Get the date filters. + $d1 = $this->dates->get('date1'); + $d2 = $this->dates->get('date2'); + $w1 = $this->dates->get('when1'); + $w2 = $this->dates->get('when2'); + + // Process the date filters. + if (!empty($d1) || !empty($d2)) + { + $this->processDates($d1, $d2, $w1, $w2); + } + + // Process the input string. + $this->processString($this->input, $this->language, $this->mode); + + // Get the number of matching terms. + foreach ($this->included as $token) + { + $this->terms += count($token->matches); + } + + // Remove the temporary date storage. + unset($this->dates); + + /* + * Lastly, determine whether this query can return a result set. + */ + // Check if we have a query string. + if (!empty($this->input)) + { + $this->search = true; + } + // Check if we can search without a query string. + elseif ($this->empty && (!empty($this->filter) || !empty($this->filters) || !empty($this->date1) || !empty($this->date2))) + { + $this->search = true; + } + // We do not have a valid search query. + else + { + $this->search = false; + } + } + + /** + * Method to convert the query object into a URI string. + * + * @param string $base The base URI. [optional] + * + * @return string The complete query URI. + * + * @since 2.5 + */ + public function toURI($base = null) + { + // Set the base if not specified. + if (empty($base)) + { + $base = 'index.php?option=com_finder&view=search'; + } + + // Get the base URI. + $uri = JUri::getInstance($base); + + // Add the static taxonomy filter if present. + if (!empty($this->filter)) + { + $uri->setVar('f', $this->filter); + } + + // Get the filters in the request. + $input = JFactory::getApplication()->input; + $t = $input->request->get('t', array(), 'array'); + + // Add the dynamic taxonomy filters if present. + if (!empty($this->filters)) + { + foreach ($this->filters as $nodes) + { + foreach ($nodes as $node) + { + if (!in_array($node, $t)) + { + continue; + } + $uri->setVar('t[]', $node); + } + } + } + + // Add the input string if present. + if (!empty($this->input)) + { + $uri->setVar('q', $this->input); + } + + // Add the start date if present. + if (!empty($this->date1)) + { + $uri->setVar('d1', $this->date1); + } + + // Add the end date if present. + if (!empty($this->date2)) + { + $uri->setVar('d2', $this->date2); + } + + // Add the start date modifier if present. + if (!empty($this->when1)) + { + $uri->setVar('w1', $this->when1); + } + + // Add the end date modifier if present. + if (!empty($this->when2)) + { + $uri->setVar('w2', $this->when2); + } + + // Add a menu item id if one is not present. + if (!$uri->getVar('Itemid')) + { + // Get the menu item id. + $query = array( + 'view' => $uri->getVar('view'), + 'f' => $uri->getVar('f'), + 'q' => $uri->getVar('q') + ); + $item = FinderHelperRoute::getItemid($query); + + // Add the menu item id if present. + if ($item !== null) + { + $uri->setVar('Itemid', $item); + } + } + + return $uri->toString(array('path', 'query')); + } + + /** + * Method to get a list of excluded search term ids. + * + * @return array An array of excluded term ids. + * + * @since 2.5 + */ + public function getExcludedTermIds() + { + $results = array(); + + // Iterate through the excluded tokens and compile the matching terms. + for ($i = 0, $c = count($this->excluded); $i < $c; $i++) + { + $results = array_merge($results, $this->excluded[$i]->matches); + } + + // Sanitize the terms. + $results = array_unique($results); + JArrayHelper::toInteger($results); + + return $results; + } + + /** + * Method to get a list of included search term ids. + * + * @return array An array of included term ids. + * + * @since 2.5 + */ + public function getIncludedTermIds() + { + $results = array(); + + // Iterate through the included tokens and compile the matching terms. + for ($i = 0, $c = count($this->included); $i < $c; $i++) + { + // Check if we have any terms. + if (empty($this->included[$i]->matches)) + { + continue; + } + + // Get the term. + $term = $this->included[$i]->term; + + // Prepare the container for the term if necessary. + if (!array_key_exists($term, $results)) + { + $results[$term] = array(); + } + + // Add the matches to the stack. + $results[$term] = array_merge($results[$term], $this->included[$i]->matches); + } + + // Sanitize the terms. + foreach ($results as $key => $value) + { + $results[$key] = array_unique($results[$key]); + JArrayHelper::toInteger($results[$key]); + } + + return $results; + } + + /** + * Method to get a list of required search term ids. + * + * @return array An array of required term ids. + * + * @since 2.5 + */ + public function getRequiredTermIds() + { + $results = array(); + + // Iterate through the included tokens and compile the matching terms. + for ($i = 0, $c = count($this->included); $i < $c; $i++) + { + // Check if the token is required. + if ($this->included[$i]->required) + { + // Get the term. + $term = $this->included[$i]->term; + + // Prepare the container for the term if necessary. + if (!array_key_exists($term, $results)) + { + $results[$term] = array(); + } + + // Add the matches to the stack. + $results[$term] = array_merge($results[$term], $this->included[$i]->matches); + } + } + + // Sanitize the terms. + foreach ($results as $key => $value) + { + $results[$key] = array_unique($results[$key]); + JArrayHelper::toInteger($results[$key]); + } + + return $results; + } + + /** + * Method to process the static taxonomy input. The static taxonomy input + * comes in the form of a pre-defined search filter that is assigned to the + * search form. + * + * @param integer $filterId The id of static filter. + * + * @return boolean True on success, false on failure. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function processStaticTaxonomy($filterId) + { + // Get the database object. + $db = JFactory::getDbo(); + + // Initialize user variables + $user = JFactory::getUser(); + $groups = implode(',', $user->getAuthorisedViewLevels()); + + // Load the predefined filter. + $query = $db->getQuery(true) + ->select('f.data, f.params') + ->from($db->quoteName('#__finder_filters') . ' AS f') + ->where('f.filter_id = ' . (int) $filterId); + + $db->setQuery($query); + $return = $db->loadObject(); + + // Check the returned filter. + if (empty($return)) + { + return false; + } + + // Set the filter. + $this->filter = (int) $filterId; + + // Get a parameter object for the filter date options. + $registry = new JRegistry; + $registry->loadString($return->params); + $params = $registry; + + // Set the dates if not already set. + $this->dates->def('d1', $params->get('d1')); + $this->dates->def('d2', $params->get('d2')); + $this->dates->def('w1', $params->get('w1')); + $this->dates->def('w2', $params->get('w2')); + + // Remove duplicates and sanitize. + $filters = explode(',', $return->data); + $filters = array_unique($filters); + JArrayHelper::toInteger($filters); + + // Remove any values of zero. + if (array_search(0, $filters, true) !== false) + { + unset($filters[array_search(0, $filters, true)]); + } + + // Check if we have any real input. + if (empty($filters)) + { + return true; + } + + /* + * Create the query to get filters from the database. We do this for + * two reasons: one, it allows us to ensure that the filters being used + * are real; two, we need to sort the filters by taxonomy branch. + */ + $query->clear() + ->select('t1.id, t1.title, t2.title AS branch') + ->from($db->quoteName('#__finder_taxonomy') . ' AS t1') + ->join('INNER', $db->quoteName('#__finder_taxonomy') . ' AS t2 ON t2.id = t1.parent_id') + ->where('t1.state = 1') + ->where('t1.access IN (' . $groups . ')') + ->where('t1.id IN (' . implode(',', $filters) . ')') + ->where('t2.state = 1') + ->where('t2.access IN (' . $groups . ')'); + + // Load the filters. + $db->setQuery($query); + $results = $db->loadObjectList(); + + // Sort the filter ids by branch. + foreach ($results as $result) + { + $this->filters[$result->branch][$result->title] = (int) $result->id; + } + + return true; + } + + /** + * Method to process the dynamic taxonomy input. The dynamic taxonomy input + * comes in the form of select fields that the user chooses from. The + * dynamic taxonomy input is processed AFTER the static taxonomy input + * because the dynamic options can be used to further narrow a static + * taxonomy filter. + * + * @param array $filters An array of taxonomy node ids. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function processDynamicTaxonomy($filters) + { + // Initialize user variables + $user = JFactory::getUser(); + $groups = implode(',', $user->getAuthorisedViewLevels()); + + // Remove duplicates and sanitize. + $filters = array_unique($filters); + JArrayHelper::toInteger($filters); + + // Remove any values of zero. + if (array_search(0, $filters, true) !== false) + { + unset($filters[array_search(0, $filters, true)]); + } + + // Check if we have any real input. + if (empty($filters)) + { + return true; + } + + // Get the database object. + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + /* + * Create the query to get filters from the database. We do this for + * two reasons: one, it allows us to ensure that the filters being used + * are real; two, we need to sort the filters by taxonomy branch. + */ + $query->select('t1.id, t1.title, t2.title AS branch') + ->from($db->quoteName('#__finder_taxonomy') . ' AS t1') + ->join('INNER', $db->quoteName('#__finder_taxonomy') . ' AS t2 ON t2.id = t1.parent_id') + ->where('t1.state = 1') + ->where('t1.access IN (' . $groups . ')') + ->where('t1.id IN (' . implode(',', $filters) . ')') + ->where('t2.state = 1') + ->where('t2.access IN (' . $groups . ')'); + + // Load the filters. + $db->setQuery($query); + $results = $db->loadObjectList(); + + // Cleared filter branches. + $cleared = array(); + + /* + * Sort the filter ids by branch. Because these filters are designed to + * override and further narrow the items selected in the static filter, + * we will clear the values from the static filter on a branch by + * branch basis before adding the dynamic filters. So, if the static + * filter defines a type filter of "articles" and three "category" + * filters but the user only limits the category further, the category + * filters will be flushed but the type filters will not. + */ + foreach ($results as $result) + { + // Check if the branch has been cleared. + if (!in_array($result->branch, $cleared)) + { + // Clear the branch. + $this->filters[$result->branch] = array(); + + // Add the branch to the cleared list. + $cleared[] = $result->branch; + } + + // Add the filter to the list. + $this->filters[$result->branch][$result->title] = (int) $result->id; + } + + return true; + } + + /** + * Method to process the query date filters to determine start and end + * date limitations. + * + * @param string $date1 The first date filter. + * @param string $date2 The second date filter. + * @param string $when1 The first date modifier. + * @param string $when2 The second date modifier. + * + * @return boolean True on success. + * + * @since 2.5 + */ + protected function processDates($date1, $date2, $when1, $when2) + { + // Clean up the inputs. + $date1 = JString::trim(JString::strtolower($date1)); + $date2 = JString::trim(JString::strtolower($date2)); + $when1 = JString::trim(JString::strtolower($when1)); + $when2 = JString::trim(JString::strtolower($when2)); + + // Get the time offset. + $offset = JFactory::getApplication()->getCfg('offset'); + + // Array of allowed when values. + $whens = array('before', 'after', 'exact'); + + // The value of 'today' is a special case that we need to handle. + if ($date1 === JString::strtolower(JText::_('COM_FINDER_QUERY_FILTER_TODAY'))) + { + $today = JFactory::getDate('now', $offset); + $date1 = $today->format('%Y-%m-%d'); + } + + // Try to parse the date string. + $date = JFactory::getDate($date1, $offset); + + // Check if the date was parsed successfully. + if ($date->toUnix() !== null) + { + // Set the date filter. + $this->date1 = $date->toSQL(); + $this->when1 = in_array($when1, $whens) ? $when1 : 'before'; + } + + // The value of 'today' is a special case that we need to handle. + if ($date2 === JString::strtolower(JText::_('COM_FINDER_QUERY_FILTER_TODAY'))) + { + $today = JFactory::getDate('now', $offset); + $date2 = $today->format('%Y-%m-%d'); + } + + // Try to parse the date string. + $date = JFactory::getDate($date2, $offset); + + // Check if the date was parsed successfully. + if ($date->toUnix() !== null) + { + // Set the date filter. + $this->date2 = $date->toSQL(); + $this->when2 = in_array($when2, $whens) ? $when2 : 'before'; + } + + return true; + } + + /** + * Method to process the query input string and extract required, optional, + * and excluded tokens; taxonomy filters; and date filters. + * + * @param string $input The query input string. + * @param string $lang The query input language. + * @param string $mode The query matching mode. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function processString($input, $lang, $mode) + { + // Clean up the input string. + $input = html_entity_decode($input, ENT_QUOTES, 'UTF-8'); + $input = JString::strtolower($input); + $input = preg_replace('#\s+#mi', ' ', $input); + $input = JString::trim($input); + $debug = JFactory::getConfig()->get('debug_lang'); + + /* + * First, we need to handle string based modifiers. String based + * modifiers could potentially include things like "category:blah" or + * "before:2009-10-21" or "type:article", etc. + */ + $patterns = array( + 'before' => JText::_('COM_FINDER_FILTER_WHEN_BEFORE'), + 'after' => JText::_('COM_FINDER_FILTER_WHEN_AFTER') + ); + + // Add the taxonomy branch titles to the possible patterns. + foreach (FinderIndexerTaxonomy::getBranchTitles() as $branch) + { + // Add the pattern. + $patterns[$branch] = JString::strtolower(JText::_(FinderHelperLanguage::branchSingular($branch))); + } + + // Container for search terms and phrases. + $terms = array(); + $phrases = array(); + + // Cleared filter branches. + $cleared = array(); + + /* + * Compile the suffix pattern. This is used to match the values of the + * filter input string. Single words can be input directly, multi-word + * values have to be wrapped in double quotes. + */ + $quotes = html_entity_decode('‘’'', ENT_QUOTES, 'UTF-8'); + $suffix = '(([\w\d' . $quotes . '-]+)|\"([\w\d\s' . $quotes . '-]+)\")'; + + /* + * Iterate through the possible filter patterns and search for matches. + * We need to match the key, colon, and a value pattern for the match + * to be valid. + */ + foreach ($patterns as $modifier => $pattern) + { + $matches = array(); + + if ($debug) + { + $pattern = substr($pattern, 2, -2); + } + + // Check if the filter pattern is in the input string. + if (preg_match('#' . $pattern . '\s*:\s*' . $suffix . '#mi', $input, $matches)) + { + // Get the value given to the modifier. + $value = isset($matches[3]) ? $matches[3] : $matches[1]; + + // Now we have to handle the filter string. + switch ($modifier) + { + // Handle a before and after date filters. + case 'before': + case 'after': + { + // Get the time offset. + $offset = JFactory::getApplication()->getCfg('offset'); + + // Array of allowed when values. + $whens = array('before', 'after', 'exact'); + + // The value of 'today' is a special case that we need to handle. + if ($value === JString::strtolower(JText::_('COM_FINDER_QUERY_FILTER_TODAY'))) + { + $today = JFactory::getDate('now', $offset); + $value = $today->format('%Y-%m-%d'); + } + + // Try to parse the date string. + $date = JFactory::getDate($value, $offset); + + // Check if the date was parsed successfully. + if ($date->toUnix() !== null) + { + // Set the date filter. + $this->date1 = $date->toSQL(); + $this->when1 = in_array($modifier, $whens) ? $modifier : 'before'; + } + + break; + } + + // Handle a taxonomy branch filter. + default: + { + // Try to find the node id. + $return = FinderIndexerTaxonomy::getNodeByTitle($modifier, $value); + + // Check if the node id was found. + if ($return) + { + // Check if the branch has been cleared. + if (!in_array($modifier, $cleared)) + { + // Clear the branch. + $this->filters[$modifier] = array(); + + // Add the branch to the cleared list. + $cleared[] = $modifier; + } + + // Add the filter to the list. + $this->filters[$modifier][$return->title] = (int) $return->id; + } + + break; + } + } + + // Clean up the input string again. + $input = str_replace($matches[0], '', $input); + $input = preg_replace('#\s+#mi', ' ', $input); + $input = JString::trim($input); + } + } + + /* + * Extract the tokens enclosed in double quotes so that we can handle + * them as phrases. + */ + if (JString::strpos($input, '"') !== false) + { + $matches = array(); + + // Extract the tokens enclosed in double quotes. + if (preg_match_all('#\"([^"]+)\"#mi', $input, $matches)) + { + /* + * One or more phrases were found so we need to iterate through + * them, tokenize them as phrases, and remove them from the raw + * input string before we move on to the next processing step. + */ + foreach ($matches[1] as $key => $match) + { + // Find the complete phrase in the input string. + $pos = JString::strpos($input, $matches[0][$key]); + $len = JString::strlen($matches[0][$key]); + + // Add any terms that are before this phrase to the stack. + if (JString::trim(JString::substr($input, 0, $pos))) + { + $terms = array_merge($terms, explode(' ', JString::trim(JString::substr($input, 0, $pos)))); + } + + // Strip out everything up to and including the phrase. + $input = JString::substr($input, $pos + $len); + + // Clean up the input string again. + $input = preg_replace('#\s+#mi', ' ', $input); + $input = JString::trim($input); + + // Get the number of words in the phrase. + $parts = explode(' ', $match); + + // Check if the phrase is longer than three words. + if (count($parts) > 3) + { + /* + * If the phrase is longer than three words, we need to + * break it down into smaller chunks of phrases that + * are less than or equal to three words. We overlap + * the chunks so that we can ensure that a match is + * found for the complete phrase and not just portions + * of it. + */ + for ($i = 0, $c = count($parts); $i < $c; $i += 2) + { + // Set up the chunk. + $chunk = array(); + + // The chunk has to be assembled based on how many + // pieces are available to use. + switch ($c - $i) + { + /* + * If only one word is left, we can break from + * the switch and loop because the last word + * was already used at the end of the last + * chunk. + */ + case 1: + break 2; + + // If there words are left, we use them both as + // the last chunk of the phrase and we're done. + case 2: + $chunk[] = $parts[$i]; + $chunk[] = $parts[$i + 1]; + break; + + // If there are three or more words left, we + // build a three word chunk and continue on. + default: + $chunk[] = $parts[$i]; + $chunk[] = $parts[$i + 1]; + $chunk[] = $parts[$i + 2]; + break; + } + + // If the chunk is not empty, add it as a phrase. + if (count($chunk)) + { + $phrases[] = implode(' ', $chunk); + $terms[] = implode(' ', $chunk); + } + } + } + else + { + // The phrase is <= 3 words so we can use it as is. + $phrases[] = $match; + $terms[] = $match; + } + } + } + } + + // Add the remaining terms if present. + if (!empty($input)) + { + $terms = array_merge($terms, explode(' ', $input)); + } + + // An array of our boolean operators. $operator => $translation + $operators = array( + 'AND' => JString::strtolower(JText::_('COM_FINDER_QUERY_OPERATOR_AND')), + 'OR' => JString::strtolower(JText::_('COM_FINDER_QUERY_OPERATOR_OR')), + 'NOT' => JString::strtolower(JText::_('COM_FINDER_QUERY_OPERATOR_NOT')) + ); + + // If language debugging is enabled you need to ignore the debug strings in matching. + if (JDEBUG) + { + $debugStrings = array('**', '??'); + $operators = str_replace($debugStrings, '', $operators); + } + + /* + * Iterate through the terms and perform any sorting that needs to be + * done based on boolean search operators. Terms that are before an + * and/or/not modifier have to be handled in relation to their operator. + */ + for ($i = 0, $c = count($terms); $i < $c; $i++) + { + // Check if the term is followed by an operator that we understand. + if (isset($terms[$i + 1]) && in_array($terms[$i + 1], $operators)) + { + // Get the operator mode. + $op = array_search($terms[$i + 1], $operators); + + // Handle the AND operator. + if ($op === 'AND' && isset($terms[$i + 2])) + { + // Tokenize the current term. + $token = FinderIndexerHelper::tokenize($terms[$i], $lang, true); + $token = $this->getTokenData($token); + + // Set the required flag. + $token->required = true; + + // Add the current token to the stack. + $this->included[] = $token; + $this->highlight = array_merge($this->highlight, array_keys($token->matches)); + + // Skip the next token (the mode operator). + $this->operators[] = $terms[$i + 1]; + + // Tokenize the term after the next term (current plus two). + $other = FinderIndexerHelper::tokenize($terms[$i + 2], $lang, true); + $other = $this->getTokenData($other); + + // Set the required flag. + $other->required = true; + + // Add the token after the next token to the stack. + $this->included[] = $other; + $this->highlight = array_merge($this->highlight, array_keys($other->matches)); + + // Remove the processed phrases if possible. + if (($pk = array_search($terms[$i], $phrases)) !== false) + { + unset($phrases[$pk]); + } + if (($pk = array_search($terms[$i + 2], $phrases)) !== false) + { + unset($phrases[$pk]); + } + + // Remove the processed terms. + unset($terms[$i]); + unset($terms[$i + 1]); + unset($terms[$i + 2]); + + // Adjust the loop. + $i += 2; + continue; + } + // Handle the OR operator. + elseif ($op === 'OR' && isset($terms[$i + 2])) + { + // Tokenize the current term. + $token = FinderIndexerHelper::tokenize($terms[$i], $lang, true); + $token = $this->getTokenData($token); + + // Set the required flag. + $token->required = false; + + // Add the current token to the stack. + if (count($token->matches)) + { + $this->included[] = $token; + $this->highlight = array_merge($this->highlight, array_keys($token->matches)); + } + else + { + $this->ignored[] = $token; + } + + // Skip the next token (the mode operator). + $this->operators[] = $terms[$i + 1]; + + // Tokenize the term after the next term (current plus two). + $other = FinderIndexerHelper::tokenize($terms[$i + 2], $lang, true); + $other = $this->getTokenData($other); + + // Set the required flag. + $other->required = false; + + // Add the token after the next token to the stack. + if (count($other->matches)) + { + $this->included[] = $other; + $this->highlight = array_merge($this->highlight, array_keys($other->matches)); + } + else + { + $this->ignored[] = $other; + } + + // Remove the processed phrases if possible. + if (($pk = array_search($terms[$i], $phrases)) !== false) + { + unset($phrases[$pk]); + } + if (($pk = array_search($terms[$i + 2], $phrases)) !== false) + { + unset($phrases[$pk]); + } + + // Remove the processed terms. + unset($terms[$i]); + unset($terms[$i + 1]); + unset($terms[$i + 2]); + + // Adjust the loop. + $i += 2; + continue; + } + } + // Handle an orphaned OR operator. + elseif (isset($terms[$i + 1]) && array_search($terms[$i], $operators) === 'OR') + { + // Skip the next token (the mode operator). + $this->operators[] = $terms[$i]; + + // Tokenize the next term (current plus one). + $other = FinderIndexerHelper::tokenize($terms[$i + 1], $lang, true); + $other = $this->getTokenData($other); + + // Set the required flag. + $other->required = false; + + // Add the token after the next token to the stack. + if (count($other->matches)) + { + $this->included[] = $other; + $this->highlight = array_merge($this->highlight, array_keys($other->matches)); + } + else + { + $this->ignored[] = $other; + } + + // Remove the processed phrase if possible. + if (($pk = array_search($terms[$i + 1], $phrases)) !== false) + { + unset($phrases[$pk]); + } + + // Remove the processed terms. + unset($terms[$i]); + unset($terms[$i + 1]); + + // Adjust the loop. + $i += 1; + continue; + } + // Handle the NOT operator. + elseif (isset($terms[$i + 1]) && array_search($terms[$i], $operators) === 'NOT') + { + // Skip the next token (the mode operator). + $this->operators[] = $terms[$i]; + + // Tokenize the next term (current plus one). + $other = FinderIndexerHelper::tokenize($terms[$i + 1], $lang, true); + $other = $this->getTokenData($other); + + // Set the required flag. + $other->required = false; + + // Add the next token to the stack. + if (count($other->matches)) + { + $this->excluded[] = $other; + } + else + { + $this->ignored[] = $other; + } + + // Remove the processed phrase if possible. + if (($pk = array_search($terms[$i + 1], $phrases)) !== false) + { + unset($phrases[$pk]); + } + + // Remove the processed terms. + unset($terms[$i]); + unset($terms[$i + 1]); + + // Adjust the loop. + $i += 1; + continue; + } + } + + /* + * Iterate through any search phrases and tokenize them. We handle + * phrases as autonomous units and do not break them down into two and + * three word combinations. + */ + for ($i = 0, $c = count($phrases); $i < $c; $i++) + { + // Tokenize the phrase. + $token = FinderIndexerHelper::tokenize($phrases[$i], $lang, true); + $token = $this->getTokenData($token); + + // Set the required flag. + $token->required = true; + + // Add the current token to the stack. + $this->included[] = $token; + $this->highlight = array_merge($this->highlight, array_keys($token->matches)); + + // Remove the processed term if possible. + if (($pk = array_search($phrases[$i], $terms)) !== false) + { + unset($terms[$pk]); + } + + // Remove the processed phrase. + unset($phrases[$i]); + } + + /* + * Handle any remaining tokens using the standard processing mechanism. + */ + if (!empty($terms)) + { + // Tokenize the terms. + $terms = implode(' ', $terms); + $tokens = FinderIndexerHelper::tokenize($terms, $lang, false); + + // Make sure we are working with an array. + $tokens = is_array($tokens) ? $tokens : array($tokens); + + // Get the token data and required state for all the tokens. + foreach ($tokens as $token) + { + // Get the token data. + $token = $this->getTokenData($token); + + // Set the required flag for the token. + $token->required = $mode === 'AND' ? ($token->phrase ? false : true) : false; + + // Add the token to the appropriate stack. + if (count($token->matches) || $token->required) + { + $this->included[] = $token; + $this->highlight = array_merge($this->highlight, array_keys($token->matches)); + } + else + { + $this->ignored[] = $token; + } + } + } + + return true; + } + + /** + * Method to get the base and similar term ids and, if necessary, suggested + * term data from the database. The terms ids are identified based on a + * 'like' match in MySQL and/or a common stem. If no term ids could be + * found, then we know that we will not be able to return any results for + * that term and we should try to find a similar term to use that we can + * match so that we can suggest the alternative search query to the user. + * + * @param FinderIndexerToken $token A FinderIndexerToken object. + * + * @return FinderIndexerToken A FinderIndexerToken object. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected function getTokenData($token) + { + // Get the database object. + $db = JFactory::getDbo(); + + // Create a database query to build match the token. + $query = $db->getQuery(true) + ->select('t.term, t.term_id') + ->from('#__finder_terms AS t'); + + /* + * If the token is a phrase, the lookup process is fairly simple. If + * the token is a word, it is a little more complicated. We have to + * create two queries to lookup the term and the stem respectively, + * then union the result sets together. This is MUCH faster than using + * an or condition in the database query. + */ + if ($token->phrase) + { + // Add the phrase to the query. + $query->where('t.term = ' . $db->quote($token->term)) + ->where('t.phrase = 1'); + } + else + { + // Add the term to the query. + $query->where('t.term = ' . $db->quote($token->term)) + ->where('t.phrase = 0'); + + // Clone the query, replace the WHERE clause. + $sub = clone($query); + $sub->clear('where'); + $sub->where('t.stem = ' . $db->quote($token->stem)); + $sub->where('t.phrase = 0'); + + // Union the two queries. + $query->union($sub); + } + + // Get the terms. + $db->setQuery($query); + $matches = $db->loadObjectList(); + + // Setup the container. + $token->matches = array(); + + // Check the matching terms. + if (!empty($matches)) + { + // Add the matches to the token. + for ($i = 0, $c = count($matches); $i < $c; $i++) + { + $token->matches[$matches[$i]->term] = (int) $matches[$i]->term_id; + } + } + + // If no matches were found, try to find a similar but better token. + if (empty($token->matches)) + { + // Create a database query to get the similar terms. + // TODO: PostgreSQL doesn't support SOUNDEX out of the box + $query->clear() + ->select('DISTINCT t.term_id AS id, t.term AS term') + ->from('#__finder_terms AS t') + // ->where('t.soundex = ' . soundex($db->quote($token->term))) + ->where('t.soundex = SOUNDEX(' . $db->quote($token->term) . ')') + ->where('t.phrase = ' . (int) $token->phrase); + + // Get the terms. + $db->setQuery($query); + $results = $db->loadObjectList(); + + // Check if any similar terms were found. + if (empty($results)) + { + return $token; + } + + // Stack for sorting the similar terms. + $suggestions = array(); + + // Get the levnshtein distance for all suggested terms. + foreach ($results as $sk => $st) + { + // Get the levenshtein distance between terms. + $distance = levenshtein($st->term, $token->term); + + // Make sure the levenshtein distance isn't over 50. + if ($distance < 50) + { + $suggestions[$sk] = $distance; + } + } + + // Sort the suggestions. + asort($suggestions, SORT_NUMERIC); + + // Get the closest match. + $keys = array_keys($suggestions); + $key = $keys[0]; + + // Add the suggested term. + $token->suggestion = $results[$key]->term; + } + + return $token; + } +} diff --git a/administrator/components/com_finder/helpers/indexer/result.php b/administrator/components/com_finder/helpers/indexer/result.php new file mode 100644 index 0000000..1d05bea --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/result.php @@ -0,0 +1,431 @@ + array('title', 'subtitle', 'id'), + FinderIndexer::TEXT_CONTEXT => array('summary', 'body'), + FinderIndexer::META_CONTEXT => array('meta', 'list_price', 'sale_price'), + FinderIndexer::PATH_CONTEXT => array('path', 'alias'), + FinderIndexer::MISC_CONTEXT => array('comments') + ); + + /** + * The indexer will use this data to create taxonomy mapping entries for + * the item so that it can be filtered by type, label, category, + * or whatever. + * + * @var array + * @since 2.5 + */ + protected $taxonomy = array(); + + /** + * The content URL. + * + * @var string + * @since 2.5 + */ + public $url; + + /** + * The content route. + * + * @var string + * @since 2.5 + */ + public $route; + + /** + * The content title. + * + * @var string + * @since 2.5 + */ + public $title; + + /** + * The content description. + * + * @var string + * @since 2.5 + */ + public $description; + + /** + * The published state of the result. + * + * @var integer + * @since 2.5 + */ + public $published; + + /** + * The content published state. + * + * @var integer + * @since 2.5 + */ + public $state; + + /** + * The content access level. + * + * @var integer + * @since 2.5 + */ + public $access; + + /** + * The content language. + * + * @var string + * @since 2.5 + */ + public $language = '*'; + + /** + * The publishing start date. + * + * @var string + * @since 2.5 + */ + public $publish_start_date; + + /** + * The publishing end date. + * + * @var string + * @since 2.5 + */ + public $publish_end_date; + + /** + * The generic start date. + * + * @var string + * @since 2.5 + */ + public $start_date; + + /** + * The generic end date. + * + * @var string + * @since 2.5 + */ + public $end_date; + + /** + * The item list price. + * + * @var mixed + * @since 2.5 + */ + public $list_price; + + /** + * The item sale price. + * + * @var mixed + * @since 2.5 + */ + public $sale_price; + + /** + * The content type id. This is set by the adapter. + * + * @var integer + * @since 2.5 + */ + public $type_id; + + /** + * The default language for content. + * + * @var string + * @since 3.0.2 + */ + public $defaultLanguage; + + /** + * Constructor + * + * @since 3.0.3 + */ + public function __construct() + { + $this->defaultLanguage = JComponentHelper::getParams('com_languages')->get('site', 'en-GB'); + } + + /** + * The magic set method is used to push additional values into the elements + * array in order to preserve the cleanliness of the object. + * + * @param string $name The name of the element. + * @param mixed $value The value of the element. + * + * @return void + * + * @since 2.5 + */ + public function __set($name, $value) + { + $this->elements[$name] = $value; + } + + /** + * The magic get method is used to retrieve additional element values + * from the elements array. + * + * @param string $name The name of the element. + * + * @return mixed The value of the element if set, null otherwise. + * + * @since 2.5 + */ + public function __get($name) + { + // Get the element value if set. + if (array_key_exists($name, $this->elements)) + { + return $this->elements[$name]; + } + else + { + return null; + } + } + + /** + * The magic isset method is used to check the state of additional element + * values in the elements array. + * + * @param string $name The name of the element. + * + * @return boolean True if set, false otherwise. + * + * @since 2.5 + */ + public function __isset($name) + { + return isset($this->elements[$name]); + } + + /** + * The magic unset method is used to unset additional element values in the + * elements array. + * + * @param string $name The name of the element. + * + * @return void + * + * @since 2.5 + */ + public function __unset($name) + { + unset($this->elements[$name]); + } + + /** + * Method to retrieve additional element values from the elements array. + * + * @param string $name The name of the element. + * + * @return mixed The value of the element if set, null otherwise. + * + * @since 2.5 + */ + public function getElement($name) + { + // Get the element value if set. + if (array_key_exists($name, $this->elements)) + { + return $this->elements[$name]; + } + else + { + return null; + } + } + + /** + * Method to set additional element values in the elements array. + * + * @param string $name The name of the element. + * @param mixed $value The value of the element. + * + * @return void + * + * @since 2.5 + */ + public function setElement($name, $value) + { + $this->elements[$name] = $value; + } + + /** + * Method to get all processing instructions. + * + * @return array An array of processing instructions. + * + * @since 2.5 + */ + public function getInstructions() + { + return $this->instructions; + } + + /** + * Method to add a processing instruction for an item property. + * + * @param string $group The group to associate the property with. + * @param string $property The property to process. + * + * @return void + * + * @since 2.5 + */ + public function addInstruction($group, $property) + { + // Check if the group exists. We can't add instructions for unknown groups. + if (array_key_exists($group, $this->instructions)) + { + // Check if the property exists in the group. + if (!in_array($property, $this->instructions[$group])) + { + // Add the property to the group. + $this->instructions[$group][] = $property; + } + } + } + + /** + * Method to remove a processing instruction for an item property. + * + * @param string $group The group to associate the property with. + * @param string $property The property to process. + * + * @return void + * + * @since 2.5 + */ + public function removeInstruction($group, $property) + { + // Check if the group exists. We can't remove instructions for unknown groups. + if (array_key_exists($group, $this->instructions)) + { + // Search for the property in the group. + $key = array_search($property, $this->instructions[$group]); + + // If the property was found, remove it. + if ($key !== false) + { + unset($this->instructions[$group][$key]); + } + } + } + + /** + * Method to get the taxonomy maps for an item. + * + * @param string $branch The taxonomy branch to get. [optional] + * + * @return array An array of taxonomy maps. + * + * @since 2.5 + */ + public function getTaxonomy($branch = null) + { + // Get the taxonomy branch if available. + if ($branch !== null && isset($this->taxonomy[$branch])) + { + // Filter the input. + $branch = preg_replace('#[^\pL\pM\pN\p{Pi}\p{Pf}\'+-.,]+#mui', ' ', $branch); + + return $this->taxonomy[$branch]; + } + + return $this->taxonomy; + } + + /** + * Method to add a taxonomy map for an item. + * + * @param string $branch The title of the taxonomy branch to add the node to. + * @param string $title The title of the taxonomy node. + * @param integer $state The published state of the taxonomy node. [optional] + * @param integer $access The access level of the taxonomy node. [optional] + * + * @return void + * + * @since 2.5 + */ + public function addTaxonomy($branch, $title, $state = 1, $access = 1) + { + // Filter the input. + $branch = preg_replace('#[^\pL\pM\pN\p{Pi}\p{Pf}\'+-.,]+#mui', ' ', $branch); + + // Create the taxonomy node. + $node = new JObject; + $node->title = $title; + $node->state = (int) $state; + $node->access = (int) $access; + + // Add the node to the taxonomy branch. + $this->taxonomy[$branch][$node->title] = $node; + } + + /** + * Method to set the item language + * + * @return void + * + * @since 3.0 + */ + public function setLanguage() + { + if ($this->language == '*' || $this->language == '') + { + $this->language = $this->defaultLanguage; + } + } +} diff --git a/administrator/components/com_finder/helpers/indexer/stemmer.php b/administrator/components/com_finder/helpers/indexer/stemmer.php new file mode 100644 index 0000000..d2c9a81 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/stemmer.php @@ -0,0 +1,87 @@ +clean($adapter, 'cmd'); + $path = __DIR__ . '/stemmer/' . $adapter . '.php'; + $class = 'FinderIndexerStemmer' . ucfirst($adapter); + + // Check if a stemmer exists for the adapter. + if (file_exists($path)) + { + // Instantiate the stemmer. + include_once $path; + $instances[$adapter] = new $class; + } + else + { + // Throw invalid adapter exception. + throw new Exception(JText::sprintf('COM_FINDER_INDEXER_INVALID_STEMMER', $adapter)); + } + + return $instances[$adapter]; + } + + /** + * Method to stem a token and return the root. + * + * @param string $token The token to stem. + * @param string $lang The language of the token. + * + * @return string The root token. + * + * @since 2.5 + */ + abstract public function stem($token, $lang); +} diff --git a/administrator/components/com_finder/helpers/indexer/stemmer/fr.php b/administrator/components/com_finder/helpers/indexer/stemmer/fr.php new file mode 100644 index 0000000..05c9556 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/stemmer/fr.php @@ -0,0 +1,264 @@ +cache[$lang][$token])) + { + // Stem the token. + $result = static::_getStem($token); + + // Add the token to the cache. + $this->cache[$lang][$token] = $result; + } + + return $this->cache[$lang][$token]; + } + + /** + * French stemmer rules variables. + * + * @return array The rules + * + * @since 3.0 + */ + protected static function getStemRules() + { + if (static::$_stemRules) + { + return static::$_stemRules; + } + + $vars = array(); + + // French accented letters in ISO-8859-1 encoding + $vars['accents'] = chr(224) . chr(226) . chr(232) . chr(233) . chr(234) . chr(235) . chr(238) . chr(239) . chr(244) . chr(251) . chr(249) . chr(231); + + // The rule patterns include all accented words for french language + $vars['rule_pattern'] = "/^([a-z" . $vars['accents'] . "]*)(\*){0,1}(\d)([a-z" . $vars['accents'] . "]*)([.|>])/"; + + // French vowels (including y) in ISO-8859-1 encoding + $vars['vowels'] = chr(97) . chr(224) . chr(226) . chr(101) . chr(232) . chr(233) . chr(234) . chr(235) . chr(105) . chr(238) . chr(239) . chr(111) . chr(244) . chr(117) . chr(251) . chr(249) . chr(121); + + // The French rules in ISO-8859-1 encoding + $vars['rules'] = array( + 'esre1>', 'esio1>', 'siol1.', 'siof0.', 'sioe0.', 'sio3>', 'st1>', 'sf1>', 'sle1>', 'slo1>', 's' . chr(233) . '1>', chr(233) . 'tuae5.', + chr(233) . 'tuae2.', 'tnia0.', 'tniv1.', 'tni3>', 'suor1.', 'suo0.', 'sdrail5.', 'sdrai4.', 'er' . chr(232) . 'i1>', 'sesue3x>', + 'esuey5i.', 'esue2x>', 'se1>', 'er' . chr(232) . 'g3.', 'eca1>', 'esiah0.', 'esi1>', 'siss2.', 'sir2>', 'sit2>', 'egan' . chr(233) . '1.', + 'egalli6>', 'egass1.', 'egas0.', 'egat3.', 'ega3>', 'ette4>', 'ett2>', 'etio1.', 'tio' . chr(231) . '4c.', 'tio0.', 'et1>', 'eb1>', + 'snia1>', 'eniatnau8>', 'eniatn4.', 'enia1>', 'niatnio3.', 'niatg3.', 'e' . chr(233) . '1>', chr(233) . 'hcat1.', chr(233) . 'hca4.', + chr(233) . 'tila5>', chr(233) . 'tici5.', chr(233) . 'tir1.', chr(233) . 'ti3>', chr(233) . 'gan1.', chr(233) . 'ga3>', + chr(233) . 'tehc1.', chr(233) . 'te3>', chr(233) . 'it0.', chr(233) . '1>', 'eire4.', 'eirue5.', 'eio1.', 'eia1.', 'ei1>', 'eng1.', + 'xuaessi7.', 'xuae1>', 'uaes0.', 'uae3.', 'xuave2l.', 'xuav2li>', 'xua3la>', 'ela1>', 'lart2.', 'lani2>', 'la' . chr(233) . '2>', + 'siay4i.', 'siassia7.', 'siarv1*.', 'sia1>', 'tneiayo6i.', 'tneiay6i.', 'tneiassia9.', 'tneiareio7.', 'tneia5>', 'tneia4>', 'tiario4.', + 'tiarim3.', 'tiaria3.', 'tiaris3.', 'tiari5.', 'tiarve6>', 'tiare5>', 'iare4>', 'are3>', 'tiay4i.', 'tia3>', 'tnay4i.', + 'em' . chr(232) . 'iu5>', 'em' . chr(232) . 'i4>', 'tnaun3.', 'tnauqo3.', 'tnau4>', 'tnaf0.', 'tnat' . chr(233) . '2>', 'tna3>', 'tno3>', + 'zeiy4i.', 'zey3i.', 'zeire5>', 'zeird4.', 'zeirio4.', 'ze2>', 'ssiab0.', 'ssia4.', 'ssi3.', 'tnemma6>', 'tnemesuey9i.', 'tnemesue8>', + 'tnemevi7.', 'tnemessia5.', 'tnemessi8.', 'tneme5>', 'tnemia4.', 'tnem' . chr(233) . '5>', 'el2l>', 'lle3le>', 'let' . chr(244) . '0.', + 'lepp0.', 'le2>', 'srei1>', 'reit3.', 'reila2.', 'rei3>', 'ert' . chr(226) . 'e5.', 'ert' . chr(226) . chr(233) . '1.', + 'ert' . chr(226) . '4.', 'drai4.', 'erdro0.', 'erute5.', 'ruta0.', 'eruta1.', 'erutiov1.', 'erub3.', 'eruh3.', 'erul3.', 'er2r>', 'nn1>', + 'r' . chr(232) . 'i3.', 'srev0.', 'sr1>', 'rid2>', 're2>', 'xuei4.', 'esuei5.', 'lbati3.', 'lba3>', 'rueis0.', 'ruehcn4.', 'ecirta6.', + 'ruetai6.', 'rueta5.', 'rueir0.', 'rue3>', 'esseti6.', 'essere6>', 'esserd1.', 'esse4>', 'essiab1.', 'essia5.', 'essio1.', 'essi4.', + 'essal4.', 'essa1>', 'ssab1.', 'essurp1.', 'essu4.', 'essi1.', 'ssor1.', 'essor2.', 'esso1>', 'ess2>', 'tio3.', 'r' . chr(232) . 's2re.', + 'r' . chr(232) . '0e.', 'esn1.', 'eu1>', 'sua0.', 'su1>', 'utt1>', 'tu' . chr(231) . '3c.', 'u' . chr(231) . '2c.', 'ur1.', 'ehcn2>', + 'ehcu1>', 'snorr3.', 'snoru3.', 'snorua3.', 'snorv3.', 'snorio4.', 'snori5.', 'snore5>', 'snortt4>', 'snort' . chr(238) . 'a7.', 'snort3.', + 'snor4.', 'snossi6.', 'snoire6.', 'snoird5.', 'snoitai7.', 'snoita6.', 'snoits1>', 'noits0.', 'snoi4>', 'noitaci7>', 'noitai6.', 'noita5.', + 'noitu4.', 'noi3>', 'snoya0.', 'snoy4i.', 'sno' . chr(231) . 'a1.', 'sno' . chr(231) . 'r1.', 'snoe4.', 'snosiar1>', 'snola1.', 'sno3>', + 'sno1>', 'noll2.', 'tnennei4.', 'ennei2>', 'snei1>', 'sne' . chr(233) . '1>', 'enne' . chr(233) . '5e.', 'ne' . chr(233) . '3e.', 'neic0.', + 'neiv0.', 'nei3.', 'sc1.', 'sd1.', 'sg1.', 'sni1.', 'tiu0.', 'ti2.', 'sp1>', 'sna1>', 'sue1.', 'enn2>', 'nong2.', 'noss2.', 'rioe4.', + 'riot0.', 'riorc1.', 'riovec5.', 'rio3.', 'ric2.', 'ril2.', 'tnerim3.', 'tneris3>', 'tneri5.', 't' . chr(238) . 'a3.', 'riss2.', + 't' . chr(238) . '2.', 't' . chr(226) . '2>', 'ario2.', 'arim1.', 'ara1.', 'aris1.', 'ari3.', 'art1>', 'ardn2.', 'arr1.', 'arua1.', + 'aro1.', 'arv1.', 'aru1.', 'ar2.', 'rd1.', 'ud1.', 'ul1.', 'ini1.', 'rin2.', 'tnessiab3.', 'tnessia7.', 'tnessi6.', 'tnessni4.', 'sini2.', + 'sl1.', 'iard3.', 'iario3.', 'ia2>', 'io0.', 'iule2.', 'i1>', 'sid2.', 'sic2.', 'esoi4.', 'ed1.', 'ai2>', 'a1>', 'adr1.', + 'tner' . chr(232) . '5>', 'evir1.', 'evio4>', 'evi3.', 'fita4.', 'fi2>', 'enie1.', 'sare4>', 'sari4>', 'sard3.', 'sart2>', 'sa2.', + 'tnessa6>', 'tnessu6>', 'tnegna3.', 'tnegi3.', 'tneg0.', 'tneru5>', 'tnemg0.', 'tnerni4.', 'tneiv1.', 'tne3>', 'une1.', 'en1>', 'nitn2.', + 'ecnay5i.', 'ecnal1.', 'ecna4.', 'ec1>', 'nn1.', 'rit2>', 'rut2>', 'rud2.', 'ugn1>', 'eg1>', 'tuo0.', 'tul2>', 't' . chr(251) . '2>', + 'ev1>', 'v' . chr(232) . '2ve>', 'rtt1>', 'emissi6.', 'em1.', 'ehc1.', 'c' . chr(233) . 'i2c' . chr(232) . '.', 'libi2l.', 'llie1.', + 'liei4i.', 'xuev1.', 'xuey4i.', 'xueni5>', 'xuell4.', 'xuere5.', 'xue3>', 'rb' . chr(233) . '3rb' . chr(232) . '.', 'tur2.', + 'rir' . chr(233) . '4re.', 'rir2.', 'c' . chr(226) . '2ca.', 'snu1.', 'rt' . chr(238) . 'a4.', 'long2.', 'vec2.', chr(231) . '1c>', + 'ssilp3.', 'silp2.', 't' . chr(232) . 'hc2te.', 'n' . chr(232) . 'm2ne.', 'llepp1.', 'tan2.', 'rv' . chr(232) . '3rve.', + 'rv' . chr(233) . '3rve.', 'r' . chr(232) . '2re.', 'r' . chr(233) . '2re.', 't' . chr(232) . '2te.', 't' . chr(233) . '2te.', 'epp1.', + 'eya2i.', 'ya1i.', 'yo1i.', 'esu1.', 'ugi1.', 'tt1.', 'end0.' + ); + + static::$_stemRules = $vars; + + return static::$_stemRules; + } + + /** + * Returns the number of the first rule from the rule number + * that can be applied to the given reversed input. + * returns -1 if no rule can be applied, ie the stem has been found + * + * @param string $reversed_input The input to check in reversed order + * @param integer $rule_number The rule number to check + * + * @return integer Number of the first rule + * + * @since 3.0 + */ + private static function _getFirstRule($reversed_input, $rule_number) + { + $vars = static::getStemRules(); + + $nb_rules = count($vars['rules']); + + for ($i = $rule_number; $i < $nb_rules; $i++) + { + // Gets the letters from the current rule + $rule = $vars['rules'][$i]; + $rule = preg_replace($vars['rule_pattern'], "\\1", $rule); + + if (strncasecmp(utf8_decode($rule), $reversed_input, strlen(utf8_decode($rule))) == 0) + { + return $i; + } + } + + return -1; + } + + /** + * Check the acceptability of a stem for French language + * + * @param string $reversed_stem The stem to check in reverse form + * + * @return boolean True if stem is acceptable + * + * @since 3.0 + */ + private static function _check($reversed_stem) + { + $vars = static::getStemRules(); + + if (preg_match('/[' . $vars['vowels'] . ']$/', utf8_encode($reversed_stem))) + { + // If the form starts with a vowel then at least two letters must remain after stemming (e.g.: "etaient" --> "et") + return (strlen($reversed_stem) > 2); + } + else + { + // If the reversed stem starts with a consonant then at least two letters must remain after stemming + if (strlen($reversed_stem) <= 2) + { + return false; + } + + // And at least one of these must be a vowel or "y" + return (preg_match('/[' . $vars['vowels'] . ']/', utf8_encode($reversed_stem))); + } + } + + /** + * Paice/Husk stemmer which returns a stem for the given $input + * + * @param string $input The word for which we want the stem in UTF-8 + * + * @return string The stem + * + * @since 3.0 + */ + private static function _getStem($input) + { + $vars = static::getStemRules(); + + $intact = true; + $reversed_input = strrev(utf8_decode($input)); + $rule_number = 0; + + // This loop goes through the rules' array until it finds an ending one (ending by '.') or the last one ('end0.') + while (true) + { + $rule_number = static::_getFirstRule($reversed_input, $rule_number); + + if ($rule_number == -1) + { + // No other rule can be applied => the stem has been found + break; + } + $rule = $vars['rules'][$rule_number]; + preg_match($vars['rule_pattern'], $rule, $matches); + + if (($matches[2] != '*') || ($intact)) + { + $reversed_stem = utf8_decode($matches[4]) . substr($reversed_input, $matches[3], strlen($reversed_input) - $matches[3]); + + if (self::_check($reversed_stem)) + { + $reversed_input = $reversed_stem; + + if ($matches[5] == '.') + { + break; + } + } + else + { + // Go to another rule + $rule_number++; + } + } + else + { + // Go to another rule + $rule_number++; + } + } + + return utf8_encode(strrev($reversed_input)); + } +} diff --git a/administrator/components/com_finder/helpers/indexer/stemmer/index.html b/administrator/components/com_finder/helpers/indexer/stemmer/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/stemmer/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/helpers/indexer/stemmer/porter_en.php b/administrator/components/com_finder/helpers/indexer/stemmer/porter_en.php new file mode 100644 index 0000000..330143f --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/stemmer/porter_en.php @@ -0,0 +1,448 @@ +cache[$lang][$token])) + { + // Stem the token. + $result = $token; + $result = self::_step1ab($result); + $result = self::_step1c($result); + $result = self::_step2($result); + $result = self::_step3($result); + $result = self::_step4($result); + $result = self::_step5($result); + + // Add the token to the cache. + $this->cache[$lang][$token] = $result; + } + + return $this->cache[$lang][$token]; + } + + /** + * Step 1 + * + * @param string $word The token to stem. + * + * @return string + * + * @since 2.5 + */ + private static function _step1ab($word) + { + // Part a + if (substr($word, -1) == 's') + { + self::_replace($word, 'sses', 'ss') + or self::_replace($word, 'ies', 'i') + or self::_replace($word, 'ss', 'ss') + or self::_replace($word, 's', ''); + } + + // Part b + if (substr($word, -2, 1) != 'e' or !self::_replace($word, 'eed', 'ee', 0)) + { + // First rule + $v = self::$_regex_vowel; + + // Words ending with ing and ed + // Note use of && and OR, for precedence reasons + if (preg_match("#$v+#", substr($word, 0, -3)) && self::_replace($word, 'ing', '') + or preg_match("#$v+#", substr($word, 0, -2)) && self::_replace($word, 'ed', '')) + { + // If one of above two test successful + if (!self::_replace($word, 'at', 'ate') and !self::_replace($word, 'bl', 'ble') and !self::_replace($word, 'iz', 'ize')) + { + // Double consonant ending + if (self::_doubleConsonant($word) and substr($word, -2) != 'll' and substr($word, -2) != 'ss' and substr($word, -2) != 'zz') + { + $word = substr($word, 0, -1); + } + elseif (self::_m($word) == 1 and self::_cvc($word)) + { + $word .= 'e'; + } + } + } + } + + return $word; + } + + /** + * Step 1c + * + * @param string $word The token to stem. + * + * @return string + * + * @since 2.5 + */ + private static function _step1c($word) + { + $v = self::$_regex_vowel; + + if (substr($word, -1) == 'y' && preg_match("#$v+#", substr($word, 0, -1))) + { + self::_replace($word, 'y', 'i'); + } + + return $word; + } + + /** + * Step 2 + * + * @param string $word The token to stem. + * + * @return string + * + * @since 2.5 + */ + private static function _step2($word) + { + switch (substr($word, -2, 1)) + { + case 'a': + self::_replace($word, 'ational', 'ate', 0) + or self::_replace($word, 'tional', 'tion', 0); + break; + case 'c': + self::_replace($word, 'enci', 'ence', 0) + or self::_replace($word, 'anci', 'ance', 0); + break; + case 'e': + self::_replace($word, 'izer', 'ize', 0); + break; + case 'g': + self::_replace($word, 'logi', 'log', 0); + break; + case 'l': + self::_replace($word, 'entli', 'ent', 0) + or self::_replace($word, 'ousli', 'ous', 0) + or self::_replace($word, 'alli', 'al', 0) + or self::_replace($word, 'bli', 'ble', 0) + or self::_replace($word, 'eli', 'e', 0); + break; + case 'o': + self::_replace($word, 'ization', 'ize', 0) + or self::_replace($word, 'ation', 'ate', 0) + or self::_replace($word, 'ator', 'ate', 0); + break; + case 's': + self::_replace($word, 'iveness', 'ive', 0) + or self::_replace($word, 'fulness', 'ful', 0) + or self::_replace($word, 'ousness', 'ous', 0) + or self::_replace($word, 'alism', 'al', 0); + break; + case 't': + self::_replace($word, 'biliti', 'ble', 0) + or self::_replace($word, 'aliti', 'al', 0) + or self::_replace($word, 'iviti', 'ive', 0); + break; + } + + return $word; + } + + /** + * Step 3 + * + * @param string $word The token to stem. + * + * @return string + * + * @since 2.5 + */ + private static function _step3($word) + { + switch (substr($word, -2, 1)) + { + case 'a': + self::_replace($word, 'ical', 'ic', 0); + break; + case 's': + self::_replace($word, 'ness', '', 0); + break; + case 't': + self::_replace($word, 'icate', 'ic', 0) + or self::_replace($word, 'iciti', 'ic', 0); + break; + case 'u': + self::_replace($word, 'ful', '', 0); + break; + case 'v': + self::_replace($word, 'ative', '', 0); + break; + case 'z': + self::_replace($word, 'alize', 'al', 0); + break; + } + + return $word; + } + + /** + * Step 4 + * + * @param string $word The token to stem. + * + * @return string + * + * @since 2.5 + */ + private static function _step4($word) + { + switch (substr($word, -2, 1)) + { + case 'a': + self::_replace($word, 'al', '', 1); + break; + case 'c': + self::_replace($word, 'ance', '', 1) + or self::_replace($word, 'ence', '', 1); + break; + case 'e': + self::_replace($word, 'er', '', 1); + break; + case 'i': + self::_replace($word, 'ic', '', 1); + break; + case 'l': + self::_replace($word, 'able', '', 1) + or self::_replace($word, 'ible', '', 1); + break; + case 'n': + self::_replace($word, 'ant', '', 1) + or self::_replace($word, 'ement', '', 1) + or self::_replace($word, 'ment', '', 1) + or self::_replace($word, 'ent', '', 1); + break; + case 'o': + if (substr($word, -4) == 'tion' or substr($word, -4) == 'sion') + { + self::_replace($word, 'ion', '', 1); + } + else + { + self::_replace($word, 'ou', '', 1); + } + break; + case 's': + self::_replace($word, 'ism', '', 1); + break; + case 't': + self::_replace($word, 'ate', '', 1) + or self::_replace($word, 'iti', '', 1); + break; + case 'u': + self::_replace($word, 'ous', '', 1); + break; + case 'v': + self::_replace($word, 'ive', '', 1); + break; + case 'z': + self::_replace($word, 'ize', '', 1); + break; + } + + return $word; + } + + /** + * Step 5 + * + * @param string $word The token to stem. + * + * @return string + * + * @since 2.5 + */ + private static function _step5($word) + { + // Part a + if (substr($word, -1) == 'e') + { + if (self::_m(substr($word, 0, -1)) > 1) + { + self::_replace($word, 'e', ''); + } + elseif (self::_m(substr($word, 0, -1)) == 1) + { + if (!self::_cvc(substr($word, 0, -1))) + { + self::_replace($word, 'e', ''); + } + } + } + + // Part b + if (self::_m($word) > 1 and self::_doubleConsonant($word) and substr($word, -1) == 'l') + { + $word = substr($word, 0, -1); + } + + return $word; + } + + /** + * Replaces the first string with the second, at the end of the string. If third + * arg is given, then the preceding string must match that m count at least. + * + * @param string &$str String to check + * @param string $check Ending to check for + * @param string $repl Replacement string + * @param integer $m Optional minimum number of m() to meet + * + * @return boolean Whether the $check string was at the end + * of the $str string. True does not necessarily mean + * that it was replaced. + * + * @since 2.5 + */ + private static function _replace(&$str, $check, $repl, $m = null) + { + $len = 0 - strlen($check); + + if (substr($str, $len) == $check) + { + $substr = substr($str, 0, $len); + + if (is_null($m) or self::_m($substr) > $m) + { + $str = $substr . $repl; + } + + return true; + } + + return false; + } + + /** + * m() measures the number of consonant sequences in $str. if c is + * a consonant sequence and v a vowel sequence, and <..> indicates arbitrary + * presence, + * + * gives 0 + * vc gives 1 + * vcvc gives 2 + * vcvcvc gives 3 + * + * @param string $str The string to return the m count for + * + * @return integer The m count + * + * @since 2.5 + */ + private static function _m($str) + { + $c = self::$_regex_consonant; + $v = self::$_regex_vowel; + + $str = preg_replace("#^$c+#", '', $str); + $str = preg_replace("#$v+$#", '', $str); + + preg_match_all("#($v+$c+)#", $str, $matches); + + return count($matches[1]); + } + + /** + * Returns true/false as to whether the given string contains two + * of the same consonant next to each other at the end of the string. + * + * @param string $str String to check + * + * @return boolean Result + * + * @since 2.5 + */ + private static function _doubleConsonant($str) + { + $c = self::$_regex_consonant; + + return preg_match("#$c{2}$#", $str, $matches) and $matches[0]{0} == $matches[0]{1}; + } + + /** + * Checks for ending CVC sequence where second C is not W, X or Y + * + * @param string $str String to check + * + * @return boolean Result + * + * @since 2.5 + */ + private static function _cvc($str) + { + $c = self::$_regex_consonant; + $v = self::$_regex_vowel; + + return preg_match("#($c$v$c)$#", $str, $matches) and strlen($matches[1]) == 3 and $matches[1]{2} != 'w' and $matches[1]{2} != 'x' + and $matches[1]{2} != 'y'; + } +} diff --git a/administrator/components/com_finder/helpers/indexer/stemmer/snowball.php b/administrator/components/com_finder/helpers/indexer/stemmer/snowball.php new file mode 100644 index 0000000..e387da4 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/stemmer/snowball.php @@ -0,0 +1,135 @@ +sef) ? $languages[0]->sef : '*'; + $lang = $defaultLang; + } + + // Stem the token if it is not in the cache. + if (!isset($this->cache[$lang][$token])) + { + // Get the stem function from the language string. + switch ($lang) + { + // Danish stemmer. + case 'da': + $function = 'stem_danish'; + break; + + // German stemmer. + case 'de': + $function = 'stem_german'; + break; + + // English stemmer. + default: + case 'en': + $function = 'stem_english'; + break; + + // Spanish stemmer. + case 'es': + $function = 'stem_spanish'; + break; + + // Finnish stemmer. + case 'fi': + $function = 'stem_finnish'; + break; + + // French stemmer. + case 'fr': + $function = 'stem_french'; + break; + + // Hungarian stemmer. + case 'hu': + $function = 'stem_hungarian'; + break; + + // Italian stemmer. + case 'it': + $function = 'stem_italian'; + break; + + // Norwegian stemmer. + case 'nb': + $function = 'stem_norwegian'; + break; + + // Dutch stemmer. + case 'nl': + $function = 'stem_dutch'; + break; + + // Portuguese stemmer. + case 'pt': + $function = 'stem_portuguese'; + break; + + // Romanian stemmer. + case 'ro': + $function = 'stem_romanian'; + break; + + // Russian stemmer. + case 'ru': + $function = 'stem_russian_unicode'; + break; + + // Swedish stemmer. + case 'sv': + $function = 'stem_swedish'; + break; + + // Turkish stemmer. + case 'tr': + $function = 'stem_turkish_unicode'; + break; + } + + // Stem the word if the stemmer method exists. + $this->cache[$lang][$token] = function_exists($function) ? $function($token) : $token; + } + + return $this->cache[$lang][$token]; + } +} diff --git a/administrator/components/com_finder/helpers/indexer/taxonomy.php b/administrator/components/com_finder/helpers/indexer/taxonomy.php new file mode 100644 index 0000000..db52c45 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/taxonomy.php @@ -0,0 +1,375 @@ +id; + } + + // Check to see if the branch is in the table. + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('*') + ->from($db->quoteName('#__finder_taxonomy')) + ->where($db->quoteName('parent_id') . ' = 1') + ->where($db->quoteName('title') . ' = ' . $db->quote($title)); + $db->setQuery($query); + + // Get the result. + $result = $db->loadObject(); + + // Check if the database matches the input data. + if (!empty($result) && $result->state == $state && $result->access == $access) + { + // The data matches, add the item to the cache. + self::$branches[$title] = $result; + + return self::$branches[$title]->id; + } + + /* + * The database did not match the input. This could be because the + * state has changed or because the branch does not exist. Let's figure + * out which case is true and deal with it. + */ + $branch = new JObject; + if (empty($result)) + { + // Prepare the branch object. + $branch->parent_id = 1; + $branch->title = $title; + $branch->state = (int) $state; + $branch->access = (int) $access; + } + else + { + // Prepare the branch object. + $branch->id = (int) $result->id; + $branch->parent_id = (int) $result->parent_id; + $branch->title = $result->title; + $branch->state = (int) $result->title; + $branch->access = (int) $result->access; + $branch->ordering = (int) $result->ordering; + } + + // Store the branch. + self::storeNode($branch); + + // Add the branch to the cache. + self::$branches[$title] = $branch; + + return self::$branches[$title]->id; + } + + /** + * Method to add a node to the taxonomy tree. + * + * @param string $branch The title of the branch to store the node in. + * @param string $title The title of the node. + * @param integer $state The published state of the node. [optional] + * @param integer $access The access state of the node. [optional] + * + * @return integer The id of the node. + * + * @since 2.5 + * @throws Exception on database error. + */ + public static function addNode($branch, $title, $state = 1, $access = 1) + { + // Check to see if the node is in the cache. + if (isset(self::$nodes[$branch][$title])) + { + return self::$nodes[$branch][$title]->id; + } + + // Get the branch id, insert it if it does not exist. + $branchId = self::addBranch($branch); + + // Check to see if the node is in the table. + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('*') + ->from($db->quoteName('#__finder_taxonomy')) + ->where($db->quoteName('parent_id') . ' = ' . $db->quote($branchId)) + ->where($db->quoteName('title') . ' = ' . $db->quote($title)); + $db->setQuery($query); + + // Get the result. + $result = $db->loadObject(); + + // Check if the database matches the input data. + if (!empty($result) && $result->state == $state && $result->access == $access) + { + // The data matches, add the item to the cache. + self::$nodes[$branch][$title] = $result; + + return self::$nodes[$branch][$title]->id; + } + + /* + * The database did not match the input. This could be because the + * state has changed or because the node does not exist. Let's figure + * out which case is true and deal with it. + */ + $node = new JObject; + if (empty($result)) + { + // Prepare the node object. + $node->parent_id = (int) $branchId; + $node->title = $title; + $node->state = (int) $state; + $node->access = (int) $access; + } + else + { + // Prepare the node object. + $node->id = (int) $result->id; + $node->parent_id = (int) $result->parent_id; + $node->title = $result->title; + $node->state = (int) $result->title; + $node->access = (int) $result->access; + $node->ordering = (int) $result->ordering; + } + + // Store the node. + self::storeNode($node); + + // Add the node to the cache. + self::$nodes[$branch][$title] = $node; + + return self::$nodes[$branch][$title]->id; + } + + /** + * Method to add a map entry between a link and a taxonomy node. + * + * @param integer $linkId The link to map to. + * @param integer $nodeId The node to map to. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + public static function addMap($linkId, $nodeId) + { + // Insert the map. + $db = JFactory::getDbo(); + + $query = $db->getQuery(true) + ->select($db->quoteName('link_id')) + ->from($db->quoteName('#__finder_taxonomy_map')) + ->where($db->quoteName('link_id') . ' = ' . (int) $linkId) + ->where($db->quoteName('node_id') . ' = ' . (int) $nodeId); + $db->setQuery($query); + $db->execute(); + $id = (int) $db->loadResult(); + + $map = new JObject; + $map->link_id = (int) $linkId; + $map->node_id = (int) $nodeId; + + if ($id) + { + $db->updateObject('#__finder_taxonomy_map', $map); + } + else + { + $db->insertObject('#__finder_taxonomy_map', $map); + } + + return true; + } + + /** + * Method to get the title of all taxonomy branches. + * + * @return array An array of branch titles. + * + * @since 2.5 + * @throws Exception on database error. + */ + public static function getBranchTitles() + { + $db = JFactory::getDbo(); + + // Set user variables + $user = JFactory::getUser(); + $groups = implode(',', $user->getAuthorisedViewLevels()); + + // Create a query to get the taxonomy branch titles. + $query = $db->getQuery(true) + ->select($db->quoteName('title')) + ->from($db->quoteName('#__finder_taxonomy')) + ->where($db->quoteName('parent_id') . ' = 1') + ->where($db->quoteName('state') . ' = 1') + ->where($db->quoteName('access') . ' IN (' . $groups . ')'); + + // Get the branch titles. + $db->setQuery($query); + $results = $db->loadColumn(); + + return $results; + } + + /** + * Method to find a taxonomy node in a branch. + * + * @param string $branch The branch to search. + * @param string $title The title of the node. + * + * @return mixed Integer id on success, null on no match. + * + * @since 2.5 + * @throws Exception on database error. + */ + public static function getNodeByTitle($branch, $title) + { + $db = JFactory::getDbo(); + + // Set user variables + $user = JFactory::getUser(); + $groups = implode(',', $user->getAuthorisedViewLevels()); + + // Create a query to get the node. + $query = $db->getQuery(true) + ->select('t1.*') + ->from($db->quoteName('#__finder_taxonomy') . ' AS t1') + ->join('INNER', $db->quoteName('#__finder_taxonomy') . ' AS t2 ON t2.id = t1.parent_id') + ->where('t1.access IN (' . $groups . ')') + ->where('t1.state = 1') + ->where('t1.title LIKE ' . $db->quote($db->escape($title) . '%')) + ->where('t2.access IN (' . $groups . ')') + ->where('t2.state = 1') + ->where('t2.title = ' . $db->quote($branch)); + + // Get the node. + $db->setQuery($query, 0, 1); + $result = $db->loadObject(); + + return $result; + } + + /** + * Method to remove map entries for a link. + * + * @param integer $linkId The link to remove. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + public static function removeMaps($linkId) + { + // Delete the maps. + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->delete($db->quoteName('#__finder_taxonomy_map')) + ->where($db->quoteName('link_id') . ' = ' . (int) $linkId); + $db->setQuery($query); + $db->execute(); + + return true; + } + + /** + * Method to remove orphaned taxonomy nodes and branches. + * + * @return integer The number of deleted rows. + * + * @since 2.5 + * @throws Exception on database error. + */ + public static function removeOrphanNodes() + { + // Delete all orphaned nodes. + $db = JFactory::getDbo(); + $query = 'DELETE t' . + ' FROM ' . $db->quoteName('#__finder_taxonomy') . ' AS t' . + ' LEFT JOIN ' . $db->quoteName('#__finder_taxonomy_map') . ' AS m ON m.node_id = t.id' . + ' WHERE t.parent_id > 1' . + ' AND m.link_id IS NULL'; + $db->setQuery($query); + $db->execute(); + + return $db->getAffectedRows(); + } + + /** + * Method to store a node to the database. This method will accept either a branch or a node. + * + * @param object $item The item to store. + * + * @return boolean True on success. + * + * @since 2.5 + * @throws Exception on database error. + */ + protected static function storeNode($item) + { + $db = JFactory::getDbo(); + + // Check if we are updating or inserting the item. + if (empty($item->id)) + { + // Insert the item. + $db->insertObject('#__finder_taxonomy', $item, 'id'); + } + else + { + // Update the item. + $db->updateObject('#__finder_taxonomy', $item, 'id'); + } + + return true; + } +} diff --git a/administrator/components/com_finder/helpers/indexer/token.php b/administrator/components/com_finder/helpers/indexer/token.php new file mode 100644 index 0000000..45a6930 --- /dev/null +++ b/administrator/components/com_finder/helpers/indexer/token.php @@ -0,0 +1,147 @@ +language = $lang; + + // Tokens can be a single word or an array of words representing a phrase. + if (is_array($term)) + { + // Populate the token instance. + $this->term = implode($spacer, $term); + $this->stem = implode($spacer, array_map(array('FinderIndexerHelper', 'stem'), $term, array($lang))); + $this->numeric = false; + $this->common = false; + $this->phrase = true; + $this->length = JString::strlen($this->term); + + /* + * Calculate the weight of the token. + * + * 1. Length of the token up to 30 and divide by 30, add 1. + * 2. Round weight to 4 decimal points. + */ + $this->weight = (($this->length >= 30 ? 30 : $this->length) / 30) + 1; + $this->weight = round($this->weight, 4); + } + else + { + // Populate the token instance. + $this->term = $term; + $this->stem = FinderIndexerHelper::stem($this->term, $lang); + $this->numeric = (is_numeric($this->term) || (bool) preg_match('#^[0-9,.\-\+]+$#', $this->term)); + $this->common = $this->numeric ? false : FinderIndexerHelper::isCommon($this->term, $lang); + $this->phrase = false; + $this->length = JString::strlen($this->term); + + /* + * Calculate the weight of the token. + * + * 1. Length of the token up to 15 and divide by 15. + * 2. If common term, divide weight by 8. + * 3. If numeric, multiply weight by 1.5. + * 4. Round weight to 4 decimal points. + */ + $this->weight = (($this->length >= 15 ? 15 : $this->length) / 15); + $this->weight = ($this->common == true ? $this->weight / 8 : $this->weight); + $this->weight = ($this->numeric == true ? $this->weight * 1.5 : $this->weight); + $this->weight = round($this->weight, 4); + } + } +} diff --git a/administrator/components/com_finder/helpers/language.php b/administrator/components/com_finder/helpers/language.php new file mode 100644 index 0000000..5c0c9d2 --- /dev/null +++ b/administrator/components/com_finder/helpers/language.php @@ -0,0 +1,110 @@ +load('com_finder', JPATH_SITE); + } + + /** + * Method to load Smart Search plug-in language files. + * + * @return void + * + * @since 2.5 + */ + public static function loadPluginLanguage() + { + static $loaded = false; + + // If already loaded, don't load again. + if ($loaded) + { + return; + } + $loaded = true; + + // Get array of all the enabled Smart Search plug-in names. + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('name') + ->from($db->quoteName('#__extensions')) + ->where($db->quoteName('type') . ' = ' . $db->quote('plugin')) + ->where($db->quoteName('folder') . ' = ' . $db->quote('finder')) + ->where($db->quoteName('enabled') . ' = 1'); + $db->setQuery($query); + $plugins = $db->loadObjectList(); + + if (empty($plugins)) + { + return; + } + + // Load generic language strings. + $lang = JFactory::getLanguage(); + $lang->load('plg_content_finder', JPATH_ADMINISTRATOR); + + // Load language file for each plug-in. + foreach ($plugins as $plugin) + { + $lang->load($plugin->name, JPATH_ADMINISTRATOR); + } + } +} diff --git a/administrator/components/com_finder/index.html b/administrator/components/com_finder/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/models/fields/directories.php b/administrator/components/com_finder/models/fields/directories.php new file mode 100644 index 0000000..d64f424 --- /dev/null +++ b/administrator/components/com_finder/models/fields/directories.php @@ -0,0 +1,95 @@ +getCfg('log_path'), + JFactory::getApplication()->getCfg('tmp_path') + ); + + // Get the base directories. + jimport('joomla.filesystem.folder'); + $dirs = JFolder::folders(JPATH_SITE, '.', false, true); + + // Iterate through the base directories and find the subdirectories. + foreach ($dirs as $dir) + { + // Check if the directory should be excluded. + if (in_array($dir, $exclude)) + { + continue; + } + + // Get the child directories. + $return = JFolder::folders($dir, '.', true, true); + + // Merge the directories. + if (is_array($return)) + { + $values[] = $dir; + $values = array_merge($values, $return); + } + } + + // Convert the values to options. + foreach ($values as $value) + { + $options[] = JHtml::_('select.option', str_replace(JPATH_SITE . '/', '', $value), str_replace(JPATH_SITE . '/', '', $values)); + } + + // Add a null option. + array_unshift($options, JHtml::_('select.option', '', '- ' . JText::_('JNONE') . ' -')); + + return $options; + } +} diff --git a/administrator/components/com_finder/models/fields/index.html b/administrator/components/com_finder/models/fields/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/models/fields/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/models/fields/searchfilter.php b/administrator/components/com_finder/models/fields/searchfilter.php new file mode 100644 index 0000000..59f3dc0 --- /dev/null +++ b/administrator/components/com_finder/models/fields/searchfilter.php @@ -0,0 +1,54 @@ +getQuery(true) + ->select('f.title AS text, f.filter_id AS value') + ->from($db->quoteName('#__finder_filters') . ' AS f') + ->where('f.state = 1') + ->order('f.title ASC'); + $db->setQuery($query); + $options = $db->loadObjectList(); + + array_unshift($options, JHtml::_('select.option', '', JText::_('COM_FINDER_SELECT_SEARCH_FILTER'), 'value', 'text')); + + return $options; + } +} diff --git a/administrator/components/com_finder/models/filter.php b/administrator/components/com_finder/models/filter.php new file mode 100644 index 0000000..83f3997 --- /dev/null +++ b/administrator/components/com_finder/models/filter.php @@ -0,0 +1,156 @@ +getState('filter.id'); + + // Get a FinderTableFilter instance. + $filter = $this->getTable(); + + // Attempt to load the row. + $return = $filter->load($filter_id); + + // Check for a database error. + if ($return === false && $filter->getError()) + { + $this->setError($filter->getError()); + return false; + } + + // Process the filter data. + if (!empty($filter->data)) + { + $filter->data = explode(',', $filter->data); + } + elseif (empty($filter->data)) + { + $filter->data = array(); + } + + // Check for a database error. + if ($this->_db->getErrorNum()) + { + $this->setError($this->_db->getErrorMsg()); + return false; + } + + return $filter; + } + + /** + * Method to get the record form. + * + * @param array $data Data for the form. [optional] + * @param boolean $loadData True if the form is to load its own data (default case), false if not. [optional] + * + * @return mixed A JForm object on success, false on failure + * + * @since 2.5 + */ + public function getForm($data = array(), $loadData = true) + { + // Get the form. + $form = $this->loadForm('com_finder.filter', 'filter', array('control' => 'jform', 'load_data' => $loadData)); + + if (empty($form)) + { + return false; + } + + return $form; + } + + /** + * Returns a JTable object, always creating it. + * + * @param string $type The table type to instantiate. [optional] + * @param string $prefix A prefix for the table class name. [optional] + * @param array $config Configuration array for model. [optional] + * + * @return JTable A database object + * + * @since 2.5 + */ + public function getTable($type = 'Filter', $prefix = 'FinderTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * + * @since 2.5 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_finder.edit.filter.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + } + + $this->preprocessData('com_finder.filter', $data); + + return $data; + } +} diff --git a/administrator/components/com_finder/models/filters.php b/administrator/components/com_finder/models/filters.php new file mode 100644 index 0000000..3a59700 --- /dev/null +++ b/administrator/components/com_finder/models/filters.php @@ -0,0 +1,136 @@ +getDbo(); + $query = $db->getQuery(true); + + // Select all fields from the table. + $query->select('a.*') + ->from($db->quoteName('#__finder_filters') . ' AS a'); + + // Join over the users for the checked out user. + $query->select('uc.name AS editor') + ->join('LEFT', $db->quoteName('#__users') . ' AS uc ON uc.id=a.checked_out'); + + // Join over the users for the author. + $query->select('ua.name AS user_name') + ->join('LEFT', $db->quoteName('#__users') . ' AS ua ON ua.id = a.created_by'); + + // Check for a search filter. + if ($this->getState('filter.search')) + { + $query->where('( a.title LIKE \'%' . $db->escape($this->getState('filter.search')) . '%\' )'); + } + + // If the model is set to check item state, add to the query. + if (is_numeric($this->getState('filter.state'))) + { + $query->where('a.state = ' . (int) $this->getState('filter.state')); + } + + // Add the list ordering clause. + $query->order($db->escape($this->getState('list.ordering') . ' ' . $db->escape($this->getState('list.direction')))); + + return $query; + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. [optional] + * + * @return string A store id. + * + * @since 2.5 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.state'); + + return parent::getStoreId($id); + } + + /** + * Method to auto-populate the model state. Calling getState in this method will result in recursion. + * + * @param string $ordering An optional ordering field. [optional] + * @param string $direction An optional direction. [optional] + * + * @return void + * + * @since 2.5 + */ + protected function populateState($ordering = null, $direction = null) + { + // Load the filter state. + $search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $state = $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string'); + $this->setState('filter.state', $state); + + // Load the parameters. + $params = JComponentHelper::getParams('com_finder'); + $this->setState('params', $params); + + // List state information. + parent::populateState('a.title', 'asc'); + } +} diff --git a/administrator/components/com_finder/models/forms/filter.xml b/administrator/components/com_finder/models/forms/filter.xml new file mode 100644 index 0000000..cbf7481 --- /dev/null +++ b/administrator/components/com_finder/models/forms/filter.xml @@ -0,0 +1,93 @@ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
diff --git a/administrator/components/com_finder/models/forms/index.html b/administrator/components/com_finder/models/forms/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/models/forms/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/models/index.html b/administrator/components/com_finder/models/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/models/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/models/index.php b/administrator/components/com_finder/models/index.php new file mode 100644 index 0000000..c70d9cf --- /dev/null +++ b/administrator/components/com_finder/models/index.php @@ -0,0 +1,410 @@ +authorise('core.delete', $this->option); + } + + /** + * Method to test whether a record can be deleted. + * + * @param object $record A record object. + * + * @return boolean True if allowed to change the state of the record. Defaults to the permission for the component. + * + * @since 2.5 + */ + protected function canEditState($record) + { + $user = JFactory::getUser(); + return $user->authorise('core.edit.state', $this->option); + } + + /** + * Method to delete one or more records. + * + * @param array &$pks An array of record primary keys. + * + * @return boolean True if successful, false if an error occurs. + * + * @since 2.5 + */ + public function delete(&$pks) + { + $dispatcher = JEventDispatcher::getInstance(); + $pks = (array) $pks; + $table = $this->getTable(); + + // Include the content plugins for the on delete events. + JPluginHelper::importPlugin('content'); + + // Iterate the items to delete each one. + foreach ($pks as $i => $pk) + { + if ($table->load($pk)) + { + if ($this->canDelete($table)) + { + $context = $this->option . '.' . $this->name; + + // Trigger the onContentBeforeDelete event. + $result = $dispatcher->trigger($this->event_before_delete, array($context, $table)); + if (in_array(false, $result, true)) + { + $this->setError($table->getError()); + return false; + } + + if (!$table->delete($pk)) + { + $this->setError($table->getError()); + return false; + } + + // Trigger the onContentAfterDelete event. + $dispatcher->trigger($this->event_after_delete, array($context, $table)); + } + else + { + // Prune items that you can't change. + unset($pks[$i]); + $error = $this->getError(); + if ($error) + { + $this->setError($error); + } + else + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED')); + } + } + } + else + { + $this->setError($table->getError()); + return false; + } + } + + // Clear the component's cache + $this->cleanCache(); + + return true; + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery A JDatabaseQuery object + * + * @since 2.5 + */ + protected function getListQuery() + { + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->select('l.*') + ->select('t.title AS t_title') + ->from($db->quoteName('#__finder_links') . ' AS l') + ->join('INNER', $db->quoteName('#__finder_types') . ' AS t ON t.id = l.type_id'); + + // Check the type filter. + if ($this->getState('filter.type')) + { + $query->where('l.type_id = ' . (int) $this->getState('filter.type')); + } + + // Check for state filter. + if (is_numeric($this->getState('filter.state'))) + { + $query->where('l.published = ' . (int) $this->getState('filter.state')); + } + + // Check the search phrase. + if ($this->getState('filter.search') != '') + { + $search = $db->escape($this->getState('filter.search')); + $query->where( + 'l.title LIKE ' . $db->quote('%' . $db->escape($search) . '%') . ' OR l.url LIKE ' . $db->quote('%' . $db->escape($search) . '%') + . ' OR l.indexdate LIKE ' . $db->quote('%' . $db->escape($search) . '%') + ); + } + + // Handle the list ordering. + $ordering = $this->getState('list.ordering'); + $direction = $this->getState('list.direction'); + if (!empty($ordering)) + { + $query->order($db->escape($ordering) . ' ' . $db->escape($direction)); + } + + return $query; + } + + /** + * Method to get the state of the Smart Search plug-ins. + * + * @return array Array of relevant plug-ins and whether they are enabled or not. + * + * @since 2.5 + */ + public function getPluginState() + { + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->select('name, enabled') + ->from($db->quoteName('#__extensions')) + ->where($db->quoteName('type') . ' = ' . $db->quote('plugin')) + ->where($db->quoteName('folder') . ' IN(' . $db->quote('system') . ',' . $db->quote('content') . ')') + ->where($db->quoteName('element') . ' = ' . $db->quote('finder')); + $db->setQuery($query); + $db->execute(); + $plugins = $db->loadObjectList('name'); + + return $plugins; + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. [optional] + * + * @return string A store id. + * + * @since 2.5 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.state'); + $id .= ':' . $this->getState('filter.type'); + + return parent::getStoreId($id); + } + + /** + * Returns a JTable object, always creating it. + * + * @param string $type The table type to instantiate. [optional] + * @param string $prefix A prefix for the table class name. [optional] + * @param array $config Configuration array for model. [optional] + * + * @return JTable A database object + * + * @since 2.5 + */ + public function getTable($type = 'Link', $prefix = 'FinderTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Method to purge the index, deleting all links. + * + * @return boolean True on success, false on failure. + * + * @since 2.5 + * @throws Exception on database error + */ + public function purge() + { + $db = $this->getDbo(); + + // Truncate the links table. + $db->truncateTable('#__finder_links'); + + // Truncate the links terms tables. + for ($i = 0; $i <= 15; $i++) + { + // Get the mapping table suffix. + $suffix = dechex($i); + + $db->truncateTable('#__finder_links_terms' . $suffix); + } + + // Truncate the terms table. + $db->truncateTable('#__finder_terms'); + + // Truncate the taxonomy map table. + $db->truncateTable('#__finder_taxonomy_map'); + + // Delete all the taxonomy nodes except the root. + $query = $db->getQuery(true) + ->delete($db->quoteName('#__finder_taxonomy')) + ->where($db->quoteName('id') . ' > 1'); + $db->setQuery($query); + $db->execute(); + + // Truncate the tokens tables. + $db->truncateTable('#__finder_tokens'); + + // Truncate the tokens aggregate table. + $db->truncateTable('#__finder_tokens_aggregate'); + + return true; + } + + /** + * Method to auto-populate the model state. Calling getState in this method will result in recursion. + * + * @param string $ordering An optional ordering field. [optional] + * @param string $direction An optional direction. [optional] + * + * @return void + * + * @since 2.5 + */ + protected function populateState($ordering = null, $direction = null) + { + // Load the filter state. + $search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $state = $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string'); + $this->setState('filter.state', $state); + + $type = $this->getUserStateFromRequest($this->context . '.filter.type', 'filter_type', '', 'string'); + $this->setState('filter.type', $type); + + // Load the parameters. + $params = JComponentHelper::getParams('com_finder'); + $this->setState('params', $params); + + // List state information. + parent::populateState('l.title', 'asc'); + } + + /** + * Method to change the published state of one or more records. + * + * @param array &$pks A list of the primary keys to change. + * @param integer $value The value of the published state. [optional] + * + * @return boolean True on success. + * + * @since 2.5 + */ + public function publish(&$pks, $value = 1) + { + $dispatcher = JEventDispatcher::getInstance(); + $user = JFactory::getUser(); + $table = $this->getTable(); + $pks = (array) $pks; + + // Include the content plugins for the change of state event. + JPluginHelper::importPlugin('content'); + + // Access checks. + foreach ($pks as $i => $pk) + { + $table->reset(); + + if ($table->load($pk)) + { + if (!$this->canEditState($table)) + { + // Prune items that you can't change. + unset($pks[$i]); + $this->setError(JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED')); + return false; + } + } + } + + // Attempt to change the state of the records. + if (!$table->publish($pks, $value, $user->get('id'))) + { + $this->setError($table->getError()); + return false; + } + + $context = $this->option . '.' . $this->name; + + // Trigger the onContentChangeState event. + $result = $dispatcher->trigger('onContentChangeState', array($context, $pks, $value)); + + if (in_array(false, $result, true)) + { + $this->setError($table->getError()); + return false; + } + + // Clear the component's cache + $this->cleanCache(); + + return true; + } +} diff --git a/administrator/components/com_finder/models/indexer.php b/administrator/components/com_finder/models/indexer.php new file mode 100644 index 0000000..784b50a --- /dev/null +++ b/administrator/components/com_finder/models/indexer.php @@ -0,0 +1,21 @@ +authorise('core.delete', $this->option); + } + + /** + * Method to test whether a record can be deleted. + * + * @param object $record A record object. + * + * @return boolean True if allowed to change the state of the record. Defaults to the permission for the component. + * + * @since 2.5 + */ + protected function canEditState($record) + { + $user = JFactory::getUser(); + return $user->authorise('core.edit.state', $this->option); + } + + /** + * Method to delete one or more records. + * + * @param array &$pks An array of record primary keys. + * + * @return boolean True if successful, false if an error occurs. + * + * @since 2.5 + */ + public function delete(&$pks) + { + $dispatcher = JEventDispatcher::getInstance(); + $pks = (array) $pks; + $table = $this->getTable(); + + // Include the content plugins for the on delete events. + JPluginHelper::importPlugin('content'); + + // Iterate the items to delete each one. + foreach ($pks as $i => $pk) + { + if ($table->load($pk)) + { + if ($this->canDelete($table)) + { + $context = $this->option . '.' . $this->name; + + // Trigger the onContentBeforeDelete event. + $result = $dispatcher->trigger('onContentBeforeDelete', array($context, $table)); + if (in_array(false, $result, true)) + { + $this->setError($table->getError()); + return false; + } + + if (!$table->delete($pk)) + { + $this->setError($table->getError()); + return false; + } + + // Trigger the onContentAfterDelete event. + $dispatcher->trigger('onContentAfterDelete', array($context, $table)); + } + else + { + // Prune items that you can't change. + unset($pks[$i]); + $error = $this->getError(); + if ($error) + { + $this->setError($error); + } + else + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED')); + } + } + } + else + { + $this->setError($table->getError()); + return false; + } + } + + // Clear the component's cache + $this->cleanCache(); + + return true; + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery A JDatabaseQuery object + * + * @since 2.5 + */ + protected function getListQuery() + { + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Select all fields from the table. + $query->select('a.*') + ->from($db->quoteName('#__finder_taxonomy') . ' AS a'); + + // Self-join to get children. + $query->select('COUNT(b.id) AS num_children') + ->join('LEFT', $db->quoteName('#__finder_taxonomy') . ' AS b ON b.parent_id=a.id'); + + // Join to get the map links + $query->select('COUNT(c.node_id) AS num_nodes') + ->join('LEFT', $db->quoteName('#__finder_taxonomy_map') . ' AS c ON c.node_id=a.id') + + ->group('a.id, a.parent_id, a.title, a.state, a.access, a.ordering'); + + // If the model is set to check item state, add to the query. + if (is_numeric($this->getState('filter.state'))) + { + $query->where('a.state = ' . (int) $this->getState('filter.state')); + } + + // Filter the maps over the branch if set. + $branch_id = $this->getState('filter.branch'); + if (!empty($branch_id)) + { + $query->where('a.parent_id = ' . (int) $branch_id); + } + + // Filter the maps over the search string if set. + $search = $this->getState('filter.search'); + if (!empty($search)) + { + $query->where('a.title LIKE ' . $db->quote('%' . $search . '%')); + } + + // Handle the list ordering. + $ordering = $this->getState('list.ordering'); + $direction = $this->getState('list.direction'); + if (!empty($ordering)) + { + $query->order($db->escape($ordering) . ' ' . $db->escape($direction)); + } + + return $query; + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. [optional] + * + * @return string A store id. + * + * @since 2.5 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.state'); + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.branch'); + + return parent::getStoreId($id); + } + + /** + * Returns a JTable object, always creating it. + * + * @param string $type The table type to instantiate. [optional] + * @param string $prefix A prefix for the table class name. [optional] + * @param array $config Configuration array for model. [optional] + * + * @return JTable A database object + * + * @since 2.5 + */ + public function getTable($type = 'Map', $prefix = 'FinderTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Method to auto-populate the model state. Calling getState in this method will result in recursion. + * + * @param string $ordering An optional ordering field. [optional] + * @param string $direction An optional direction. [optional] + * + * @return void + * + * @since 2.5 + */ + protected function populateState($ordering = null, $direction = null) + { + // Load the filter state. + $search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $state = $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string'); + $this->setState('filter.state', $state); + + $branch = $this->getUserStateFromRequest($this->context . '.filter.branch', 'filter_branch', '1', 'string'); + $this->setState('filter.branch', $branch); + + // Load the parameters. + $params = JComponentHelper::getParams('com_finder'); + $this->setState('params', $params); + + // List state information. + parent::populateState('a.title', 'asc'); + } + + /** + * Method to change the published state of one or more records. + * + * @param array &$pks A list of the primary keys to change. + * @param integer $value The value of the published state. [optional] + * + * @return boolean True on success. + * + * @since 2.5 + */ + public function publish(&$pks, $value = 1) + { + $dispatcher = JEventDispatcher::getInstance(); + $user = JFactory::getUser(); + $table = $this->getTable(); + $pks = (array) $pks; + + // Include the content plugins for the change of state event. + JPluginHelper::importPlugin('content'); + + // Access checks. + foreach ($pks as $i => $pk) + { + $table->reset(); + + if ($table->load($pk)) + { + if (!$this->canEditState($table)) + { + // Prune items that you can't change. + unset($pks[$i]); + $this->setError(JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED')); + return false; + } + } + } + + // Attempt to change the state of the records. + if (!$table->publish($pks, $value, $user->get('id'))) + { + $this->setError($table->getError()); + return false; + } + + $context = $this->option . '.' . $this->name; + + // Trigger the onContentChangeState event. + $result = $dispatcher->trigger('onContentChangeState', array($context, $pks, $value)); + + if (in_array(false, $result, true)) + { + $this->setError($table->getError()); + return false; + } + + // Clear the component's cache + $this->cleanCache(); + + return true; + } + + /** + * Method to purge all maps from the taxonomy. + * + * @return boolean Returns true on success, false on failure. + * + * @since 2.5 + */ + public function purge() + { + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->delete($db->quoteName('#__finder_taxonomy')) + ->where($db->quoteName('parent_id') . ' > 1'); + $db->setQuery($query); + $db->execute(); + + $query->clear() + ->delete($db->quoteName('#__finder_taxonomy_map')) + ->where('1'); + $db->setQuery($query); + $db->execute(); + + return true; + } +} diff --git a/administrator/components/com_finder/models/statistics.php b/administrator/components/com_finder/models/statistics.php new file mode 100644 index 0000000..dd52625 --- /dev/null +++ b/administrator/components/com_finder/models/statistics.php @@ -0,0 +1,71 @@ +getDbo(); + $query = $db->getQuery(true); + $data = new JObject; + + $query->select('COUNT(term_id)') + ->from($db->quoteName('#__finder_terms')); + $db->setQuery($query); + $data->term_count = $db->loadResult(); + + $query->clear() + ->select('COUNT(link_id)') + ->from($db->quoteName('#__finder_links')); + $db->setQuery($query); + $data->link_count = $db->loadResult(); + + $query->clear() + ->select('COUNT(id)') + ->from($db->quoteName('#__finder_taxonomy')) + ->where($db->quoteName('parent_id') . ' = 1'); + $db->setQuery($query); + $data->taxonomy_branch_count = $db->loadResult(); + + $query->clear() + ->select('COUNT(id)') + ->from($db->quoteName('#__finder_taxonomy')) + ->where($db->quoteName('parent_id') . ' > 1'); + $db->setQuery($query); + $data->taxonomy_node_count = $db->loadResult(); + + $query->clear() + ->select('t.title AS type_title, COUNT(a.link_id) AS link_count') + ->from($db->quoteName('#__finder_links') . ' AS a') + ->join('INNER', $db->quoteName('#__finder_types') . ' AS t ON t.id = a.type_id') + ->group('a.type_id, t.title') + ->order($db->quoteName('type_title'), 'ASC'); + $db->setQuery($query); + $data->type_list = $db->loadObjectList(); + + return $data; + } +} diff --git a/administrator/components/com_finder/sql/index.html b/administrator/components/com_finder/sql/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/sql/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/sql/install.mysql.sql b/administrator/components/com_finder/sql/install.mysql.sql new file mode 100644 index 0000000..d00b529 --- /dev/null +++ b/administrator/components/com_finder/sql/install.mysql.sql @@ -0,0 +1,547 @@ +-- +-- Table structure for table `#__finder_filters` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_filters` ( + `filter_id` int(10) unsigned NOT NULL auto_increment, + `title` varchar(255) NOT NULL, + `alias` varchar(255) NOT NULL, + `state` tinyint(1) NOT NULL default '1', + `created` datetime NOT NULL default '0000-00-00 00:00:00', + `created_by` int(10) unsigned NOT NULL, + `created_by_alias` varchar(255) NOT NULL, + `modified` datetime NOT NULL default '0000-00-00 00:00:00', + `modified_by` int(10) unsigned NOT NULL default '0', + `checked_out` int(10) unsigned NOT NULL default '0', + `checked_out_time` datetime NOT NULL default '0000-00-00 00:00:00', + `map_count` int(10) unsigned NOT NULL default '0', + `data` text NOT NULL, + `params` mediumtext, + PRIMARY KEY (`filter_id`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links` ( + `link_id` int(10) unsigned NOT NULL auto_increment, + `url` varchar(255) NOT NULL, + `route` varchar(255) NOT NULL, + `title` varchar(255) default NULL, + `description` varchar(255) default NULL, + `indexdate` datetime NOT NULL default '0000-00-00 00:00:00', + `md5sum` varchar(32) default NULL, + `published` tinyint(1) NOT NULL default '1', + `state` int(5) default '1', + `access` int(5) default '0', + `language` varchar(8) NOT NULL, + `publish_start_date` datetime NOT NULL default '0000-00-00 00:00:00', + `publish_end_date` datetime NOT NULL default '0000-00-00 00:00:00', + `start_date` datetime NOT NULL default '0000-00-00 00:00:00', + `end_date` datetime NOT NULL default '0000-00-00 00:00:00', + `list_price` double unsigned NOT NULL default '0', + `sale_price` double unsigned NOT NULL default '0', + `type_id` int(11) NOT NULL, + `object` mediumblob NOT NULL, + PRIMARY KEY (`link_id`), + KEY `idx_type` (`type_id`), + KEY `idx_title` (`title`), + KEY `idx_md5` (`md5sum`), + KEY `idx_url` (`url`(75)), + KEY `idx_published_list` (`published`,`state`,`access`,`publish_start_date`,`publish_end_date`,`list_price`), + KEY `idx_published_sale` (`published`,`state`,`access`,`publish_start_date`,`publish_end_date`,`sale_price`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_terms0` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms0` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_terms1` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms1` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_terms2` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms2` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_terms3` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms3` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_terms4` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms4` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_terms5` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms5` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_terms6` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms6` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_terms7` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms7` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_terms8` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms8` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_terms9` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_terms9` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_termsa` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_termsa` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_termsb` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_termsb` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_termsc` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_termsc` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_termsd` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_termsd` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_termse` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_termse` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_links_termsf` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_links_termsf` ( + `link_id` int(10) unsigned NOT NULL, + `term_id` int(10) unsigned NOT NULL, + `weight` float unsigned NOT NULL, + PRIMARY KEY (`link_id`,`term_id`), + KEY `idx_term_weight` (`term_id`,`weight`), + KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_taxonomy` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_taxonomy` ( + `id` int(10) unsigned NOT NULL auto_increment, + `parent_id` int(10) unsigned NOT NULL default '0', + `title` varchar(255) NOT NULL, + `state` tinyint(1) unsigned NOT NULL default '1', + `access` tinyint(1) unsigned NOT NULL default '0', + `ordering` tinyint(1) unsigned NOT NULL default '0', + PRIMARY KEY (`id`), + KEY `parent_id` (`parent_id`), + KEY `state` (`state`), + KEY `ordering` (`ordering`), + KEY `access` (`access`), + KEY `idx_parent_published` (`parent_id`,`state`,`access`) +) DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `#__finder_taxonomy` +-- + +REPLACE INTO `#__finder_taxonomy` (`id`, `parent_id`, `title`, `state`, `access`, `ordering`) VALUES +(1, 0, 'ROOT', 0, 0, 0); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_taxonomy_map` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_taxonomy_map` ( + `link_id` int(10) unsigned NOT NULL, + `node_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`link_id`,`node_id`), + KEY `link_id` (`link_id`), + KEY `node_id` (`node_id`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_terms` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_terms` ( + `term_id` int(10) unsigned NOT NULL auto_increment, + `term` varchar(75) NOT NULL, + `stem` varchar(75) NOT NULL, + `common` tinyint(1) unsigned NOT NULL default '0', + `phrase` tinyint(1) unsigned NOT NULL default '0', + `weight` float unsigned NOT NULL default '0', + `soundex` varchar(75) NOT NULL, + `links` int(10) NOT NULL default '0', + PRIMARY KEY (`term_id`), + UNIQUE KEY `idx_term` (`term`), + KEY `idx_term_phrase` (`term`,`phrase`), + KEY `idx_stem_phrase` (`stem`,`phrase`), + KEY `idx_soundex_phrase` (`soundex`,`phrase`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_terms_common` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_terms_common` ( + `term` varchar(75) NOT NULL, + `language` varchar(3) NOT NULL, + KEY `idx_word_lang` (`term`,`language`), + KEY `idx_lang` (`language`) +) DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `#__finder_terms_common` +-- + +REPLACE INTO `#__finder_terms_common` (`term`, `language`) VALUES +('a', 'en'), +('about', 'en'), +('after', 'en'), +('ago', 'en'), +('all', 'en'), +('am', 'en'), +('an', 'en'), +('and', 'en'), +('ani', 'en'), +('any', 'en'), +('are', 'en'), +('aren''t', 'en'), +('as', 'en'), +('at', 'en'), +('be', 'en'), +('but', 'en'), +('by', 'en'), +('for', 'en'), +('from', 'en'), +('get', 'en'), +('go', 'en'), +('how', 'en'), +('if', 'en'), +('in', 'en'), +('into', 'en'), +('is', 'en'), +('isn''t', 'en'), +('it', 'en'), +('its', 'en'), +('me', 'en'), +('more', 'en'), +('most', 'en'), +('must', 'en'), +('my', 'en'), +('new', 'en'), +('no', 'en'), +('none', 'en'), +('not', 'en'), +('noth', 'en'), +('nothing', 'en'), +('of', 'en'), +('off', 'en'), +('often', 'en'), +('old', 'en'), +('on', 'en'), +('onc', 'en'), +('once', 'en'), +('onli', 'en'), +('only', 'en'), +('or', 'en'), +('other', 'en'), +('our', 'en'), +('ours', 'en'), +('out', 'en'), +('over', 'en'), +('page', 'en'), +('she', 'en'), +('should', 'en'), +('small', 'en'), +('so', 'en'), +('some', 'en'), +('than', 'en'), +('thank', 'en'), +('that', 'en'), +('the', 'en'), +('their', 'en'), +('theirs', 'en'), +('them', 'en'), +('then', 'en'), +('there', 'en'), +('these', 'en'), +('they', 'en'), +('this', 'en'), +('those', 'en'), +('thus', 'en'), +('time', 'en'), +('times', 'en'), +('to', 'en'), +('too', 'en'), +('true', 'en'), +('under', 'en'), +('until', 'en'), +('up', 'en'), +('upon', 'en'), +('use', 'en'), +('user', 'en'), +('users', 'en'), +('veri', 'en'), +('version', 'en'), +('very', 'en'), +('via', 'en'), +('want', 'en'), +('was', 'en'), +('way', 'en'), +('were', 'en'), +('what', 'en'), +('when', 'en'), +('where', 'en'), +('whi', 'en'), +('which', 'en'), +('who', 'en'), +('whom', 'en'), +('whose', 'en'), +('why', 'en'), +('wide', 'en'), +('will', 'en'), +('with', 'en'), +('within', 'en'), +('without', 'en'), +('would', 'en'), +('yes', 'en'), +('yet', 'en'), +('you', 'en'), +('your', 'en'), +('yours', 'en'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_tokens` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_tokens` ( + `term` varchar(75) NOT NULL, + `stem` varchar(75) NOT NULL, + `common` tinyint(1) unsigned NOT NULL default '0', + `phrase` tinyint(1) unsigned NOT NULL default '0', + `weight` float unsigned NOT NULL default '1', + `context` tinyint(1) unsigned NOT NULL default '2', + KEY `idx_word` (`term`), + KEY `idx_context` (`context`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_tokens_aggregate` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_tokens_aggregate` ( + `term_id` int(10) unsigned NOT NULL, + `map_suffix` char(1) NOT NULL, + `term` varchar(75) NOT NULL, + `stem` varchar(75) NOT NULL, + `common` tinyint(1) unsigned NOT NULL default '0', + `phrase` tinyint(1) unsigned NOT NULL default '0', + `term_weight` float unsigned NOT NULL, + `context` tinyint(1) unsigned NOT NULL default '2', + `context_weight` float unsigned NOT NULL, + `total_weight` float unsigned NOT NULL, + KEY `token` (`term`), + KEY `keyword_id` (`term_id`) +) DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `#__finder_types` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_types` ( + `id` int(10) unsigned NOT NULL auto_increment, + `title` varchar(100) NOT NULL, + `mime` varchar(100) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `title` (`title`) +) DEFAULT CHARSET=utf8; diff --git a/administrator/components/com_finder/sql/install.postgresql.sql b/administrator/components/com_finder/sql/install.postgresql.sql new file mode 100644 index 0000000..cd49af6 --- /dev/null +++ b/administrator/components/com_finder/sql/install.postgresql.sql @@ -0,0 +1,1055 @@ +-- +-- Table: #__finder_filters +-- +CREATE TABLE "#__finder_filters" ( + "filter_id" serial NOT NULL, + "title" character varying(255) NOT NULL, + "alias" character varying(255) NOT NULL, + "state" smallint DEFAULT 1 NOT NULL, + "created" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "created_by" integer NOT NULL, + "created_by_alias" character varying(255) NOT NULL, + "modified" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "modified_by" integer DEFAULT 0 NOT NULL, + "checked_out" integer DEFAULT 0 NOT NULL, + "checked_out_time" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "map_count" integer DEFAULT 0 NOT NULL, + "data" text NOT NULL, + "params" text, + PRIMARY KEY ("filter_id") +); + +-- +-- Table: #__finder_links +-- +CREATE TABLE "#__finder_links" ( + "link_id" serial NOT NULL, + "url" character varying(255) NOT NULL, + "route" character varying(255) NOT NULL, + "title" character varying(255) DEFAULT NULL, + "description" character varying(255) DEFAULT NULL, + "indexdate" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "md5sum" character varying(32) DEFAULT NULL, + "published" smallint DEFAULT 1 NOT NULL, + "state" integer DEFAULT 1, + "access" integer DEFAULT 0, + "language" character varying(8) NOT NULL, + "publish_start_date" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "publish_end_date" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "start_date" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "end_date" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL, + "list_price" numeric(8,2) DEFAULT 0 NOT NULL, + "sale_price" numeric(8,2) DEFAULT 0 NOT NULL, + "type_id" bigint NOT NULL, + "object" bytea NOT NULL, + PRIMARY KEY ("link_id") +); +CREATE INDEX "#__finder_links_idx_type" on "#__finder_links" ("type_id"); +CREATE INDEX "#__finder_links_idx_title" on "#__finder_links" ("title"); +CREATE INDEX "#__finder_links_idx_md5" on "#__finder_links" ("md5sum"); +CREATE INDEX "#__finder_links_idx_url" on "#__finder_links" (url(75)); +CREATE INDEX "#__finder_links_idx_published_list" on "#__finder_links" ("published", "state", "access", "publish_start_date", "publish_end_date", "list_price"); +CREATE INDEX "#__finder_links_idx_published_sale" on "#__finder_links" ("published", "state", "access", "publish_start_date", "publish_end_date", "sale_price"); + +-- +-- Table: #__finder_links_terms0 +-- +CREATE TABLE "#__finder_links_terms0" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_terms0_idx_term_weight" on "#__finder_links_terms0" ("term_id", "weight"); +CREATE INDEX "#__finder_links_terms0_idx_link_term_weight" on "#__finder_links_terms0" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_terms1 +-- +CREATE TABLE "#__finder_links_terms1" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_terms1_idx_term_weight" on "#__finder_links_terms1" ("term_id", "weight"); +CREATE INDEX "#__finder_links_terms1_idx_link_term_weight" on "#__finder_links_terms1" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_terms2 +-- +CREATE TABLE "#__finder_links_terms2" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_terms2_idx_term_weight" on "#__finder_links_terms2" ("term_id", "weight"); +CREATE INDEX "#__finder_links_terms2_idx_link_term_weight" on "#__finder_links_terms2" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_terms3 +-- +CREATE TABLE "#__finder_links_terms3" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_terms3_idx_term_weight" on "#__finder_links_terms3" ("term_id", "weight"); +CREATE INDEX "#__finder_links_terms3_idx_link_term_weight" on "#__finder_links_terms3" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_terms4 +-- +CREATE TABLE "#__finder_links_terms4" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_terms4_idx_term_weight" on "#__finder_links_terms4" ("term_id", "weight"); +CREATE INDEX "#__finder_links_terms4_idx_link_term_weight" on "#__finder_links_terms4" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_terms5 +-- +CREATE TABLE "#__finder_links_terms5" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_terms5_idx_term_weight" on "#__finder_links_terms5" ("term_id", "weight"); +CREATE INDEX "#__finder_links_terms5_idx_link_term_weight" on "#__finder_links_terms5" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_terms6 +-- +CREATE TABLE "#__finder_links_terms6" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_terms6_idx_term_weight" on "#__finder_links_terms6" ("term_id", "weight"); +CREATE INDEX "#__finder_links_terms6_idx_link_term_weight" on "#__finder_links_terms6" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_terms7 +-- +CREATE TABLE "#__finder_links_terms7" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_terms7_idx_term_weight" on "#__finder_links_terms7" ("term_id", "weight"); +CREATE INDEX "#__finder_links_terms7_idx_link_term_weight" on "#__finder_links_terms7" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_terms8 +-- +CREATE TABLE "#__finder_links_terms8" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_terms8_idx_term_weight" on "#__finder_links_terms8" ("term_id", "weight"); +CREATE INDEX "#__finder_links_terms8_idx_link_term_weight" on "#__finder_links_terms8" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_terms9 +-- +CREATE TABLE "#__finder_links_terms9" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_terms9_idx_term_weight" on "#__finder_links_terms9" ("term_id", "weight"); +CREATE INDEX "#__finder_links_terms9_idx_link_term_weight" on "#__finder_links_terms9" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_termsa +-- +CREATE TABLE "#__finder_links_termsa" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_termsa_idx_term_weight" on "#__finder_links_termsa" ("term_id", "weight"); +CREATE INDEX "#__finder_links_termsa_idx_link_term_weight" on "#__finder_links_termsa" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_termsb +-- +CREATE TABLE "#__finder_links_termsb" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_termsb_idx_term_weight" on "#__finder_links_termsb" ("term_id", "weight"); +CREATE INDEX "#__finder_links_termsb_idx_link_term_weight" on "#__finder_links_termsb" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_termsc +-- +CREATE TABLE "#__finder_links_termsc" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_termsc_idx_term_weight" on "#__finder_links_termsc" ("term_id", "weight"); +CREATE INDEX "#__finder_links_termsc_idx_link_term_weight" on "#__finder_links_termsc" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_termsd +-- +CREATE TABLE "#__finder_links_termsd" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_termsd_idx_term_weight" on "#__finder_links_termsd" ("term_id", "weight"); +CREATE INDEX "#__finder_links_termsd_idx_link_term_weight" on "#__finder_links_termsd" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_termse +-- +CREATE TABLE "#__finder_links_termse" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_termse_idx_term_weight" on "#__finder_links_termse" ("term_id", "weight"); +CREATE INDEX "#__finder_links_termse_idx_link_term_weight" on "#__finder_links_termse" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_links_termsf +-- +CREATE TABLE "#__finder_links_termsf" ( + "link_id" integer NOT NULL, + "term_id" integer NOT NULL, + "weight" numeric(8,2) NOT NULL, + PRIMARY KEY ("link_id", "term_id") +); +CREATE INDEX "#__finder_links_termsf_idx_term_weight" on "#__finder_links_termsf" ("term_id", "weight"); +CREATE INDEX "#__finder_links_termsf_idx_link_term_weight" on "#__finder_links_termsf" ("link_id", "term_id", "weight"); + +-- +-- Table: #__finder_taxonomy +-- +CREATE TABLE "#__finder_taxonomy" ( + "id" serial NOT NULL, + "parent_id" integer DEFAULT 0 NOT NULL, + "title" character varying(255) NOT NULL, + "state" smallint DEFAULT 1 NOT NULL, + "access" smallint DEFAULT 0 NOT NULL, + "ordering" smallint DEFAULT 0 NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "#__finder_taxonomy_parent_id" on "#__finder_taxonomy" ("parent_id"); +CREATE INDEX "#__finder_taxonomy_state" on "#__finder_taxonomy" ("state"); +CREATE INDEX "#__finder_taxonomy_ordering" on "#__finder_taxonomy" ("ordering"); +CREATE INDEX "#__finder_taxonomy_access" on "#__finder_taxonomy" ("access"); +CREATE INDEX "#__finder_taxonomy_idx_parent_published" on "#__finder_taxonomy" ("parent_id", "state", "access"); + +-- +-- Dumping data for table #__finder_taxonomy +-- +UPDATE "#__finder_taxonomy" SET ("id", "parent_id", "title", "state", "access", "ordering") = (1, 0, 'ROOT', 0, 0, 0) +WHERE "id"=1; + +INSERT INTO "#__finder_taxonomy" ("id", "parent_id", "title", "state", "access", "ordering") +SELECT 1, 0, 'ROOT', 0, 0, 0 WHERE 1 NOT IN +(SELECT 1 FROM "#__finder_taxonomy" WHERE "id"=1); + + + +-- +-- Table: #__finder_taxonomy_map +-- +CREATE TABLE "#__finder_taxonomy_map" ( + "link_id" integer NOT NULL, + "node_id" integer NOT NULL, + PRIMARY KEY ("link_id", "node_id") +); +CREATE INDEX "#__finder_taxonomy_map_link_id" on "#__finder_taxonomy_map" ("link_id"); +CREATE INDEX "#__finder_taxonomy_map_node_id" on "#__finder_taxonomy_map" ("node_id"); + +-- +-- Table: #__finder_terms +-- +CREATE TABLE "#__finder_terms" ( + "term_id" serial NOT NULL, + "term" character varying(75) NOT NULL, + "stem" character varying(75) NOT NULL, + "common" smallint DEFAULT 0 NOT NULL, + "phrase" smallint DEFAULT 0 NOT NULL, + "weight" numeric(8,2) DEFAULT 0 NOT NULL, + "soundex" character varying(75) NOT NULL, + "links" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("term_id"), + CONSTRAINT "#__finder_terms_idx_term" UNIQUE ("term") +); +CREATE INDEX "#__finder_terms_idx_term_phrase" on "#__finder_terms" ("term", "phrase"); +CREATE INDEX "#__finder_terms_idx_stem_phrase" on "#__finder_terms" ("stem", "phrase"); +CREATE INDEX "#__finder_terms_idx_soundex_phrase" on "#__finder_terms" ("soundex", "phrase"); + +-- +-- Table: #__finder_terms_common +-- +CREATE TABLE "#__finder_terms_common" ( + "term" character varying(75) NOT NULL, + "language" character varying(3) NOT NULL +); +CREATE INDEX "#__finder_terms_common_idx_word_lang" on "#__finder_terms_common" ("term", "language"); +CREATE INDEX "#__finder_terms_common_idx_lang" on "#__finder_terms_common" ("language"); + + +-- +-- Dumping data for table `#__finder_terms_common` +-- + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('a', 'en') WHERE "term"='a'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'a', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='a'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('about', 'en') WHERE "term"='about'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'about', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='about'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('after', 'en') WHERE "term"='after'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'after', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='after'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('ago', 'en') WHERE "term"='ago'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'ago', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='ago'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('all', 'en') WHERE "term"='all'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'all', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='all'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('am', 'en') WHERE "term"='am'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'am', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='am'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('an', 'en') WHERE "term"='an'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'an', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='an'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('and', 'en') WHERE "term"='and'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'and', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='and'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('ani', 'en') WHERE "term"='ani'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'ani', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='ani'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('any', 'en') WHERE "term"='any'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'any', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='any'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('are', 'en') WHERE "term"='are'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'are', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='are'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('aren''t', 'en') WHERE "term"='aren''t'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'aren''t', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='aren''t'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('as', 'en') WHERE "term"='as'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'as', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='as'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('at', 'en') WHERE "term"='at'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'at', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='at'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('be', 'en') WHERE "term"='be'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'be', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='be'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('but', 'en') WHERE "term"='but'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'but', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='but'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('by', 'en') WHERE "term"='by'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'by', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='by'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('for', 'en') WHERE "term"='for'; + +INSERT INTO "#__finder_terms_common" ("term", "language") SELECT 'for', 'en' WHERE 1 NOT IN +(SELECT 1 FROM "#__finder_terms_common" WHERE "term"='for'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('from', 'en') WHERE "term"='from'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'from', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='from'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('get', 'en') WHERE "term"='get'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'get', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='get'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('go', 'en') WHERE "term"='go'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'go', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='go'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('how', 'en') WHERE "term"='how'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'how', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='how'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('if', 'en') WHERE "term"='if'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'if', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='if'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('in', 'en') WHERE "term"='in'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'in', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='in'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('into', 'en') WHERE "term"='into'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'into', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='into'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('is', 'en') WHERE "term"='is'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'is', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='is'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('isn''t', 'en') WHERE "term"='isn''t'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'isn''t', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='isn''t'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('it', 'en') WHERE "term"='it'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'it', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='it'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('its', 'en') WHERE "term"='its'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'its', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='its'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('me', 'en') WHERE "term"='me'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'me', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='me'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('more', 'en') WHERE "term"='more'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'more', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='more'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('most', 'en') WHERE "term"='most'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'most', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='most'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('must', 'en') WHERE "term"='must'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'must', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='must'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('my', 'en') WHERE "term"='my'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'my', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='my'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('new', 'en') WHERE "term"='new'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'new', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='new'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('no', 'en') WHERE "term"='no'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'no', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='no'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('none', 'en') WHERE "term"='none'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'none', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='none'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('not', 'en') WHERE "term"='not'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'not', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='not'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('noth', 'en') WHERE "term"='noth'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'noth', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='noth'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('nothing', 'en') WHERE "term"='nothing'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'nothing', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='nothing'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('of', 'en') WHERE "term"='of'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'of', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='of'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('off', 'en') WHERE "term"='off'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'off', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='off'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('often', 'en') WHERE "term"='often'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'often', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='often'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('old', 'en') WHERE "term"='old'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'old', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='old'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('on', 'en') WHERE "term"='on'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'on', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='on'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('onc', 'en') WHERE "term"='onc'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'onc', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='onc'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('once', 'en') WHERE "term"='once'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'once', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='once'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('onli', 'en') WHERE "term"='onli'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'onli', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='onli'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('only', 'en') WHERE "term"='only'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'only', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='only'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('or', 'en') WHERE "term"='or'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'or', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='or'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('other', 'en') WHERE "term"='other'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'other', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='other'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('our', 'en') WHERE "term"='our'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'our', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='our'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('ours', 'en') WHERE "term"='ours'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'ours', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='ours'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('out', 'en') WHERE "term"='out'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'out', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='out'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('over', 'en') WHERE "term"='over'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'over', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='over'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('page', 'en') WHERE "term"='page'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'page', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='page'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('she', 'en') WHERE "term"='she'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'she', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='she'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('should', 'en') WHERE "term"='should'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'should', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='should'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('small', 'en') WHERE "term"='small'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'small', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='small'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('so', 'en') WHERE "term"='so'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'so', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='so'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('some', 'en') WHERE "term"='some'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'some', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='some'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('than', 'en') WHERE "term"='than'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'than', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='than'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('thank', 'en') WHERE "term"='thank'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'thank', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='thank'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('that', 'en') WHERE "term"='that'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'that', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='that'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('the', 'en') WHERE "term"='the'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'the', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='the'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('their', 'en') WHERE "term"='their'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'their', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='their'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('theirs', 'en') WHERE "term"='theirs'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'theirs', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='theirs'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('them', 'en') WHERE "term"='them'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'them', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='them'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('then', 'en') WHERE "term"='then'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'then', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='then'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('there', 'en') WHERE "term"='there'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'there', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='there'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('these', 'en') WHERE "term"='these'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'these', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='these'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('they', 'en') WHERE "term"='they'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'they', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='they'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('this', 'en') WHERE "term"='this'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'this', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='this'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('those', 'en') WHERE "term"='those'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'those', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='those'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('thus', 'en') WHERE "term"='thus'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'thus', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='thus'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('time', 'en') WHERE "term"='time'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'time', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='time'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('times', 'en') WHERE "term"='times'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'times', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='times'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('to', 'en') WHERE "term"='to'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'to', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='to'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('too', 'en') WHERE "term"='too'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'too', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='too'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('true', 'en') WHERE "term"='true'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'true', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='true'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('under', 'en')WHERE "term"='under'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'under', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='under'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('until', 'en') WHERE "term"='until'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'until', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='until'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('up', 'en') WHERE "term"='up'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'up', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='up'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('upon', 'en') WHERE "term"='upon'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'upon', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='upon'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('use', 'en') WHERE "term"='use'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'use', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='use'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('user', 'en') WHERE "term"='user'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'user', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='user'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('users', 'en') WHERE "term"='users'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'users', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='users'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('veri', 'en') WHERE "term"='veri'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'veri', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='veri'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('version', 'en') WHERE "term"='version'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'version', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='version'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('very', 'en') WHERE "term"='very'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'very', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='very'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('via', 'en') WHERE "term"='via'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'via', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='via'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('want', 'en') WHERE "term"='want'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'want', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='want'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('was', 'en') WHERE "term"='was'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'was', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='was'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('way', 'en') WHERE "term"='way'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'way', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='way'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('were', 'en') WHERE "term"='were'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'were', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='were'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('what', 'en') WHERE "term"='what'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'what', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='what'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('when', 'en') WHERE "term"='when'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'when', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='when'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('where', 'en') WHERE "term"='where'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'where', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='where'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('whi', 'en') WHERE "term"='whi'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'whi', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='whi'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('which', 'en') WHERE "term"='which'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'which', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='which'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('who', 'en') WHERE "term"='who'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'who', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='who'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('whom', 'en') WHERE "term"='whom'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'whom', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='whom'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('whose', 'en') WHERE "term"='whose'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'whose', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='whose'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('why', 'en') WHERE "term"='why'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'why', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='why'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('wide', 'en') WHERE "term"='wide'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'wide', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='wide'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('will', 'en') WHERE "term"='will'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'will', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='will'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('with', 'en') WHERE "term"='with'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'with', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='with'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('within', 'en') WHERE "term"='within'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'within', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='within'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('without', 'en') WHERE "term"='without'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'without', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='without'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('would', 'en') WHERE "term"='would'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'would', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='would'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('yes', 'en') WHERE "term"='yes'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'yes', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='yes'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('yet', 'en') WHERE "term"='yet'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'yet', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='yet'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('you', 'en') WHERE "term"='you'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'you', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='you'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('your', 'en') WHERE "term"='your'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'your', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='your'); + +-- +UPDATE "#__finder_terms_common" SET ("term", "language") = ('yours', 'en') WHERE "term"='yours'; + +INSERT INTO "#__finder_terms_common" ("term", "language") +SELECT 'yours', 'en' WHERE 1 NOT IN (SELECT 1 FROM "#__finder_terms_common" WHERE "term"='yours'); + + + +-- +-- Table: #__finder_tokens +-- +CREATE TABLE "#__finder_tokens" ( + "term" character varying(75) NOT NULL, + "stem" character varying(75) NOT NULL, + "common" smallint DEFAULT 0 NOT NULL, + "phrase" smallint DEFAULT 0 NOT NULL, + "weight" numeric(8,2) DEFAULT 1 NOT NULL, + "context" smallint DEFAULT 2 NOT NULL +); +CREATE INDEX "#__finder_tokens_idx_word" on "#__finder_tokens" ("term"); +CREATE INDEX "#__finder_tokens_idx_context" on "#__finder_tokens" ("context"); + +-- +-- Table: #__finder_tokens_aggregate +-- +CREATE TABLE "#__finder_tokens_aggregate" ( + "term_id" integer NOT NULL, + "map_suffix" character(1) NOT NULL, + "term" character varying(75) NOT NULL, + "stem" character varying(75) NOT NULL, + "common" smallint DEFAULT 0 NOT NULL, + "phrase" smallint DEFAULT 0 NOT NULL, + "term_weight" numeric(8,2) NOT NULL, + "context" smallint DEFAULT 2 NOT NULL, + "context_weight" numeric(8,2) NOT NULL, + "total_weight" numeric(8,2) NOT NULL +); +CREATE INDEX "#__finder_tokens_aggregate_token" on "#__finder_tokens_aggregate" ("term"); +CREATE INDEX "_#__finder_tokens_aggregate_keyword_id" on "#__finder_tokens_aggregate" ("term_id"); + +-- +-- Table: #__finder_types +-- +CREATE TABLE "#__finder_types" ( + "id" serial NOT NULL, + "title" character varying(100) NOT NULL, + "mime" character varying(100) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "#__finder_types_title" UNIQUE ("title") +); + diff --git a/administrator/components/com_finder/sql/uninstall.mysql.sql b/administrator/components/com_finder/sql/uninstall.mysql.sql new file mode 100644 index 0000000..89579b9 --- /dev/null +++ b/administrator/components/com_finder/sql/uninstall.mysql.sql @@ -0,0 +1,25 @@ +DROP TABLE IF EXISTS `#__finder_filters`; +DROP TABLE IF EXISTS `#__finder_links`; +DROP TABLE IF EXISTS `#__finder_links_terms0`; +DROP TABLE IF EXISTS `#__finder_links_terms1`; +DROP TABLE IF EXISTS `#__finder_links_terms2`; +DROP TABLE IF EXISTS `#__finder_links_terms3`; +DROP TABLE IF EXISTS `#__finder_links_terms4`; +DROP TABLE IF EXISTS `#__finder_links_terms5`; +DROP TABLE IF EXISTS `#__finder_links_terms6`; +DROP TABLE IF EXISTS `#__finder_links_terms7`; +DROP TABLE IF EXISTS `#__finder_links_terms8`; +DROP TABLE IF EXISTS `#__finder_links_terms9`; +DROP TABLE IF EXISTS `#__finder_links_termsa`; +DROP TABLE IF EXISTS `#__finder_links_termsb`; +DROP TABLE IF EXISTS `#__finder_links_termsc`; +DROP TABLE IF EXISTS `#__finder_links_termsd`; +DROP TABLE IF EXISTS `#__finder_links_termse`; +DROP TABLE IF EXISTS `#__finder_links_termsf`; +DROP TABLE IF EXISTS `#__finder_taxonomy`; +DROP TABLE IF EXISTS `#__finder_taxonomy_map`; +DROP TABLE IF EXISTS `#__finder_terms`; +DROP TABLE IF EXISTS `#__finder_terms_common`; +DROP TABLE IF EXISTS `#__finder_tokens`; +DROP TABLE IF EXISTS `#__finder_tokens_aggregate`; +DROP TABLE IF EXISTS `#__finder_types`; diff --git a/administrator/components/com_finder/sql/uninstall.postgresql.sql b/administrator/components/com_finder/sql/uninstall.postgresql.sql new file mode 100644 index 0000000..76d7981 --- /dev/null +++ b/administrator/components/com_finder/sql/uninstall.postgresql.sql @@ -0,0 +1,25 @@ +DROP TABLE IF EXISTS "#__finder_filters"; +DROP TABLE IF EXISTS "#__finder_links"; +DROP TABLE IF EXISTS "#__finder_links_terms0"; +DROP TABLE IF EXISTS "#__finder_links_terms1"; +DROP TABLE IF EXISTS "#__finder_links_terms2"; +DROP TABLE IF EXISTS "#__finder_links_terms3"; +DROP TABLE IF EXISTS "#__finder_links_terms4"; +DROP TABLE IF EXISTS "#__finder_links_terms5"; +DROP TABLE IF EXISTS "#__finder_links_terms6"; +DROP TABLE IF EXISTS "#__finder_links_terms7"; +DROP TABLE IF EXISTS "#__finder_links_terms8"; +DROP TABLE IF EXISTS "#__finder_links_terms9"; +DROP TABLE IF EXISTS "#__finder_links_termsa"; +DROP TABLE IF EXISTS "#__finder_links_termsb"; +DROP TABLE IF EXISTS "#__finder_links_termsc"; +DROP TABLE IF EXISTS "#__finder_links_termsd"; +DROP TABLE IF EXISTS "#__finder_links_termse"; +DROP TABLE IF EXISTS "#__finder_links_termsf"; +DROP TABLE IF EXISTS "#__finder_taxonomy"; +DROP TABLE IF EXISTS "#__finder_taxonomy_map"; +DROP TABLE IF EXISTS "#__finder_terms"; +DROP TABLE IF EXISTS "#__finder_terms_common"; +DROP TABLE IF EXISTS "#__finder_tokens"; +DROP TABLE IF EXISTS "#__finder_tokens_aggregate"; +DROP TABLE IF EXISTS "#__finder_types"; diff --git a/administrator/components/com_finder/tables/filter.php b/administrator/components/com_finder/tables/filter.php new file mode 100644 index 0000000..30fd952 --- /dev/null +++ b/administrator/components/com_finder/tables/filter.php @@ -0,0 +1,241 @@ +loadArray($array['params']); + $array['params'] = (string) $registry; + } + + return parent::bind($array, $ignore); + } + + /** + * Method to perform sanity checks on the JTable instance properties to ensure + * they are safe to store in the database. Child classes should override this + * method to make sure the data they are storing in the database is safe and + * as expected before storage. + * + * @return boolean True if the instance is sane and able to be stored in the database. + * + * @since 2.5 + */ + public function check() + { + if (trim($this->alias) == '') + { + $this->alias = $this->title; + } + + $this->alias = JApplication::stringURLSafe($this->alias); + + if (trim(str_replace('-', '', $this->alias)) == '') + { + $this->alias = JFactory::getDate()->format('Y-m-d-H-i-s'); + } + + // Check the end date is not earlier than start up. + if ($this->d2 > $this->_db->getNullDate() && $this->d2 < $this->d1) + { + // Swap the dates. + $temp = $this->d1; + $this->d1 = $this->d2; + $this->d2 = $temp; + } + + return true; + } + + /** + * Method to set the publishing state for a row or list of rows in the database + * table. The method respects checked out rows by other users and will attempt + * to checkin rows that it can after adjustments are made. + * + * @param mixed $pks An array of primary key values to update. If not + * set the instance property value is used. [optional] + * @param integer $state The publishing state. eg. [0 = unpublished, 1 = published] [optional] + * @param integer $userId The user id of the user performing the operation. [optional] + * + * @return boolean True on success. + * + * @since 2.5 + */ + public function publish($pks = null, $state = 1, $userId = 0) + { + $k = $this->_tbl_key; + + // Sanitize input. + JArrayHelper::toInteger($pks); + $userId = (int) $userId; + $state = (int) $state; + + // If there are no primary keys set check to see if the instance key is set. + if (empty($pks)) + { + if ($this->$k) + { + $pks = array($this->$k); + } + // Nothing to set publishing state on, return false. + else + { + $this->setError(JText::_('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED')); + return false; + } + } + + // Build the WHERE clause for the primary keys. + $where = $k . '=' . implode(' OR ' . $k . '=', $pks); + + // Determine if there is checkin support for the table. + if (!property_exists($this, 'checked_out') || !property_exists($this, 'checked_out_time')) + { + $checkin = ''; + } + else + { + $checkin = ' AND (checked_out = 0 OR checked_out = ' . (int) $userId . ')'; + } + + // Update the publishing state for rows with the given primary keys. + $query = $this->_db->getQuery(true) + ->update($this->_db->quoteName($this->_tbl)) + ->set($this->_db->quoteName('state') . ' = ' . (int) $state) + ->where($where); + $this->_db->setQuery($query . $checkin); + + try + { + $this->_db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + // If checkin is supported and all rows were adjusted, check them in. + if ($checkin && (count($pks) == $this->_db->getAffectedRows())) + { + // Checkin the rows. + foreach ($pks as $pk) + { + $this->checkin($pk); + } + } + + // If the JTable instance value is in the list of primary keys that were set, set the instance. + if (in_array($this->$k, $pks)) + { + $this->state = $state; + } + + $this->setError(''); + + return true; + } + + /** + * Method to store a row in the database from the JTable instance properties. + * If a primary key value is set the row with that primary key value will be + * updated with the instance property values. If no primary key value is set + * a new row will be inserted into the database with the properties from the + * JTable instance. + * + * @param boolean $updateNulls True to update fields even if they are null. [optional] + * + * @return boolean True on success. + * + * @since 2.5 + */ + public function store($updateNulls = false) + { + $date = JFactory::getDate(); + $user = JFactory::getUser(); + + if ($this->filter_id) + { + // Existing item + $this->modified = $date->toSql(); + $this->modified_by = $user->get('id'); + } + else + { + // New item. A filter's created field can be set by the user, + // so we don't touch it if it is set. + if (!(int) $this->created) + { + $this->created = $date->toSql(); + } + if (empty($this->created_by)) + { + $this->created_by = $user->get('id'); + } + } + + if (is_array($this->data)) + { + $this->map_count = count($this->data); + $this->data = implode(',', $this->data); + } + else + { + $this->map_count = 0; + $this->data = implode(',', array()); + } + + // Verify that the alias is unique + $table = JTable::getInstance('Filter', 'FinderTable'); + if ($table->load(array('alias' => $this->alias)) && ($table->filter_id != $this->filter_id || $this->filter_id == 0)) + { + $this->setError(JText::_('JLIB_DATABASE_ERROR_ARTICLE_UNIQUE_ALIAS')); + return false; + } + return parent::store($updateNulls); + } +} diff --git a/administrator/components/com_finder/tables/index.html b/administrator/components/com_finder/tables/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/tables/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/tables/link.php b/administrator/components/com_finder/tables/link.php new file mode 100644 index 0000000..057f3c6 --- /dev/null +++ b/administrator/components/com_finder/tables/link.php @@ -0,0 +1,32 @@ +_tbl_key; + + // Sanitize input. + JArrayHelper::toInteger($pks); + $state = (int) $state; + + // If there are no primary keys set check to see if the instance key is set. + if (empty($pks)) + { + if ($this->$k) + { + $pks = array($this->$k); + } + // Nothing to set publishing state on, return false. + else + { + $this->setError(JText::_('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED')); + return false; + } + } + + // Build the WHERE clause for the primary keys. + $where = $k . '=' . implode(' OR ' . $k . '=', $pks); + + // Update the publishing state for rows with the given primary keys. + $query = $this->_db->getQuery(true) + ->update($this->_db->quoteName($this->_tbl)) + ->set($this->_db->quoteName('state') . ' = ' . (int) $state) + ->where($where); + $this->_db->setQuery($query); + + try + { + $this->_db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + // If the JTable instance value is in the list of primary keys that were set, set the instance. + if (in_array($this->$k, $pks)) + { + $this->state = $state; + } + + $this->setError(''); + + return true; + } +} diff --git a/administrator/components/com_finder/views/filter/index.html b/administrator/components/com_finder/views/filter/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_finder/views/filter/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_finder/views/filter/tmpl/edit.php b/administrator/components/com_finder/views/filter/tmpl/edit.php new file mode 100644 index 0000000..992cfde --- /dev/null +++ b/administrator/components/com_finder/views/filter/tmpl/edit.php @@ -0,0 +1,86 @@ + + +
+ +
+ 'basic')); ?> + + +
+
form->getLabel('title'); ?>
+
form->getInput('title'); ?>
+
+
+
form->getLabel('alias'); ?>
+
form->getInput('alias'); ?>
+
+
+
form->getLabel('state'); ?>
+
form->getInput('state'); ?>
+
+
+
form->getLabel('map_count'); ?>
+
form->getInput('map_count'); ?>
+
+ + + + form->getGroup('params') as $field) : ?> +
+ hidden) : ?> +
label; ?>
+ +
input; ?>
+
+ + + + +
+
form->getLabel('created_by'); ?>
+
form->getInput('created_by'); ?>
+
+
+
form->getLabel('created_by_alias'); ?>
+
form->getInput('created_by_alias'); ?>
+
+
+
form->getLabel('created'); ?>
+
form->getInput('created'); ?>
+
+ item->modified_by) : ?> +
+
form->getLabel('modified_by'); ?>
+
form->getInput('modified_by'); ?>
+
+
+
form->getLabel('modified'); ?>
+
form->getInput('modified'); ?>
+
+ + + + +
+ +
+ $this->filter->data)); ?> +
+ + + +
diff --git a/administrator/components/com_finder/views/filter/tmpl/index.html b/administrator/components/com_finder/views/filter/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_finder/views/filter/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_finder/views/filter/view.html.php b/administrator/components/com_finder/views/filter/view.html.php new file mode 100644 index 0000000..58e8b17 --- /dev/null +++ b/administrator/components/com_finder/views/filter/view.html.php @@ -0,0 +1,114 @@ +filter = $this->get('Filter'); + $this->item = $this->get('Item'); + $this->form = $this->get('Form'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html'); + JHtml::addIncludePath(JPATH_SITE . '/components/com_finder/helpers/html'); + + // Configure the toolbar. + $this->addToolbar(); + + parent::display($tpl); + } + + /** + * Method to configure the toolbar for this view. + * + * @return void + * + * @since 2.5 + */ + protected function addToolbar() + { + JFactory::getApplication()->input->set('hidemainmenu', true); + + $user = JFactory::getUser(); + $userId = $user->get('id'); + $isNew = ($this->item->filter_id == 0); + $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $userId); + $canDo = FinderHelper::getActions(); + + // Configure the toolbar. + JToolbarHelper::title(JText::_('COM_FINDER_FILTER_EDIT_TOOLBAR_TITLE'), 'finder'); + + // Set the actions for new and existing records. + if ($isNew) + { + // For new records, check the create permission. + if ($canDo->get('core.create')) + { + JToolbarHelper::apply('filter.apply'); + JToolbarHelper::save('filter.save'); + JToolbarHelper::save2new('filter.save2new'); + } + JToolbarHelper::cancel('filter.cancel'); + } + else + { + // Can't save the record if it's checked out. + if (!$checkedOut) + { + // Since it's an existing record, check the edit permission. + if ($canDo->get('core.edit')) + { + JToolbarHelper::apply('filter.apply'); + JToolbarHelper::save('filter.save'); + + // We can save this record, but check the create permission to see if we can return to make a new one. + if ($canDo->get('core.create')) + { + JToolbarHelper::save2new('filter.save2new'); + } + } + } + // If an existing item, can save as a copy + if ($canDo->get('core.create')) + { + JToolbarHelper::save2copy('filter.save2copy'); + } + JToolbarHelper::cancel('filter.cancel', 'JTOOLBAR_CLOSE'); + } + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_COMPONENTS_FINDER_MANAGE_SEARCH_FILTERS_EDIT'); + } +} diff --git a/administrator/components/com_finder/views/filters/index.html b/administrator/components/com_finder/views/filters/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_finder/views/filters/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_finder/views/filters/tmpl/default.php b/administrator/components/com_finder/views/filters/tmpl/default.php new file mode 100644 index 0000000..999f7ce --- /dev/null +++ b/administrator/components/com_finder/views/filters/tmpl/default.php @@ -0,0 +1,161 @@ +get('id'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); + +JText::script('COM_FINDER_INDEX_CONFIRM_DELETE_PROMPT'); +?> + + +
+sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ +
+ +
+ + +
+
+
+ + + + + + + + + + + + + + items) == 0) : ?> + + + + + + items as $i => $item): + $canCreate = $user->authorise('core.create', 'com_finder'); + $canEdit = $user->authorise('core.edit', 'com_finder'); + $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id') || $item->checked_out == 0; + $canChange = $user->authorise('core.edit.state', 'com_finder') && $canCheckin; + ?> + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ total == 0): + echo JText::_('COM_FINDER_NO_FILTERS'); + ?> + + + + +
+ filter_id); ?> + + checked_out) + { + echo JHtml::_('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'filters.', $canCheckin); + } ?> + + + escape($item->title); ?> + escape($item->title); + } ?> + + state, $i, 'filters.', $canChange); ?> + + created_by_alias ? $item->created_by_alias : $item->user_name; ?> + + created, JText::_('DATE_FORMAT_LC4')); ?> + + map_count; ?> + + filter_id; ?> +
+ pagination->getListFooter(); ?> +
+ + + + + + +
+ diff --git a/administrator/components/com_finder/views/filters/tmpl/index.html b/administrator/components/com_finder/views/filters/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_finder/views/filters/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_finder/views/filters/view.html.php b/administrator/components/com_finder/views/filters/view.html.php new file mode 100644 index 0000000..db9530d --- /dev/null +++ b/administrator/components/com_finder/views/filters/view.html.php @@ -0,0 +1,103 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->total = $this->get('Total'); + $this->state = $this->get('State'); + + FinderHelper::addSubmenu('filters'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html'); + + // Configure the toolbar. + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Method to configure the toolbar for this view. + * + * @return void + * + * @since 2.5 + */ + protected function addToolbar() + { + $canDo = FinderHelper::getActions(); + + JToolbarHelper::title(JText::_('COM_FINDER_FILTERS_TOOLBAR_TITLE'), 'finder'); + $toolbar = JToolbar::getInstance('toolbar'); + + if ($canDo->get('core.create')) + { + JToolbarHelper::addNew('filter.add'); + JToolbarHelper::editList('filter.edit'); + JToolbarHelper::divider(); + } + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::publishList('filters.publish'); + JToolbarHelper::unpublishList('filters.unpublish'); + JToolbarHelper::divider(); + } + if ($canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'filters.delete'); + JToolbarHelper::divider(); + } + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_finder'); + } + JToolbarHelper::divider(); + $toolbar->appendButton('Popup', 'stats', 'COM_FINDER_STATISTICS', 'index.php?option=com_finder&view=statistics&tmpl=component', 550, 350); + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_COMPONENTS_FINDER_MANAGE_SEARCH_FILTERS'); + + JHtmlSidebar::setAction('index.php?option=com_finder&view=filters'); + + JHtmlSidebar::addFilter( + JText::_('COM_FINDER_INDEX_FILTER_BY_STATE'), + 'filter_state', + JHtml::_('select.options', JHtml::_('finder.statelist'), 'value', 'text', $this->state->get('filter.state')) + ); + } +} diff --git a/administrator/components/com_finder/views/index.html b/administrator/components/com_finder/views/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/views/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/views/index/index.html b/administrator/components/com_finder/views/index/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_finder/views/index/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_finder/views/index/tmpl/default.php b/administrator/components/com_finder/views/index/tmpl/default.php new file mode 100644 index 0000000..b34444a --- /dev/null +++ b/administrator/components/com_finder/views/index/tmpl/default.php @@ -0,0 +1,173 @@ +escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); + +$lang = JFactory::getLanguage(); +JText::script('COM_FINDER_INDEX_CONFIRM_PURGE_PROMPT'); +JText::script('COM_FINDER_INDEX_CONFIRM_DELETE_PROMPT'); +?> + + + +
+sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ +
+ +
+ + +
+
+
+ pluginState['plg_content_finder']->enabled) : ?> +
+ + +
+ + + + + + + + + + + + + + items) == 0) : ?> + + + + + + authorise('core.manage', 'com_finder'); ?> + items as $i => $item) : ?> + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ total == 0) + { + echo JText::_('COM_FINDER_INDEX_NO_DATA') . ' ' . JText::_('COM_FINDER_INDEX_TIP'); + } else { + echo JText::_('COM_FINDER_INDEX_NO_CONTENT'); + } + ?> +
+ link_id); ?> + + published, $i, 'index.', $canChange, 'cb'); ?> + + + escape($item->title); ?> + + + url) > 80) + { + echo substr($item->url, 0, 70) . '...'; + } else { + echo $item->url; + } + ?> + + + publish_start_date) or intval($item->publish_end_date) or intval($item->start_date) or intval($item->end_date)) : ?> + + + + t_title); + echo $lang->hasKey($key) ? JText::_($key) : $item->t_title; + ?> + + indexdate, JText::_('DATE_FORMAT_LC4')); ?> +
+ pagination->getListFooter(); ?> +
+ + + + + + +
+ diff --git a/administrator/components/com_finder/views/index/tmpl/index.html b/administrator/components/com_finder/views/index/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_finder/views/index/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_finder/views/index/view.html.php b/administrator/components/com_finder/views/index/view.html.php new file mode 100644 index 0000000..6bb3682 --- /dev/null +++ b/administrator/components/com_finder/views/index/view.html.php @@ -0,0 +1,116 @@ +items = $this->get('Items'); + $this->total = $this->get('Total'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + $this->pluginState = $this->get('pluginState'); + + FinderHelper::addSubmenu('index'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html'); + + // Configure the toolbar. + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Method to configure the toolbar for this view. + * + * @return void + * + * @since 2.5 + */ + protected function addToolbar() + { + $canDo = FinderHelper::getActions(); + + JToolbarHelper::title(JText::_('COM_FINDER_INDEX_TOOLBAR_TITLE'), 'finder'); + + $toolbar = JToolbar::getInstance('toolbar'); + $toolbar->appendButton( + 'Popup', 'archive', 'COM_FINDER_INDEX', 'index.php?option=com_finder&view=indexer&tmpl=component', 500, 210, 0, 0, + 'window.parent.location.reload()', 'COM_FINDER_HEADING_INDEXER' + ); + + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::publishList('index.publish'); + JToolbarHelper::unpublishList('index.unpublish'); + } + if ($canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'index.delete'); + } + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::trash('index.purge', 'COM_FINDER_INDEX_TOOLBAR_PURGE', false); + } + + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_finder'); + } + + $toolbar->appendButton('Popup', 'stats', 'COM_FINDER_STATISTICS', 'index.php?option=com_finder&view=statistics&tmpl=component', 550, 350); + + JToolbarHelper::help('JHELP_COMPONENTS_FINDER_MANAGE_INDEXED_CONTENT'); + + JHtmlSidebar::setAction('index.php?option=com_finder&view=index'); + + JHtmlSidebar::addFilter( + JText::_('COM_FINDER_INDEX_FILTER_BY_STATE'), + 'filter_state', + JHtml::_('select.options', JHtml::_('finder.statelist'), 'value', 'text', $this->state->get('filter.state')) + ); + + JHtmlSidebar::addFilter( + JText::_('COM_FINDER_INDEX_TYPE_FILTER'), + 'filter_type', + JHtml::_('select.options', JHtml::_('finder.typeslist'), 'value', 'text', $this->state->get('filter.type')) + ); + } +} diff --git a/administrator/components/com_finder/views/indexer/index.html b/administrator/components/com_finder/views/indexer/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_finder/views/indexer/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_finder/views/indexer/tmpl/default.php b/administrator/components/com_finder/views/indexer/tmpl/default.php new file mode 100644 index 0000000..34f3195 --- /dev/null +++ b/administrator/components/com_finder/views/indexer/tmpl/default.php @@ -0,0 +1,27 @@ + + +
+

+

+ +

+ +
+ +
+ + +
diff --git a/administrator/components/com_finder/views/indexer/tmpl/index.html b/administrator/components/com_finder/views/indexer/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_finder/views/indexer/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_finder/views/indexer/view.html.php b/administrator/components/com_finder/views/indexer/view.html.php new file mode 100644 index 0000000..0dfdd6c --- /dev/null +++ b/administrator/components/com_finder/views/indexer/view.html.php @@ -0,0 +1,39 @@ + diff --git a/administrator/components/com_finder/views/maps/tmpl/default.php b/administrator/components/com_finder/views/maps/tmpl/default.php new file mode 100644 index 0000000..954aad8 --- /dev/null +++ b/administrator/components/com_finder/views/maps/tmpl/default.php @@ -0,0 +1,137 @@ +escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); + +$lang = JFactory::getLanguage(); +JText::script('COM_FINDER_MAPS_CONFIRM_DELETE_PROMPT'); +?> + + +
+sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ +
+ +
+ + +
+
+
+ + + + + + + + + + items) == 0) : ?> + + + + + state->get('filter.branch') != 1) : ?> + + + + + + authorise('core.manage', 'com_finder'); ?> + items as $i => $item) : ?> + + + + + + + + + + + + + +
+ + + + + +
+ +
+ + +
+ id); ?> + + title); + $title = $lang->hasKey($key) ? JText::_($key) : $item->title; + ?> + state->get('filter.branch') == 1 && $item->num_children) : ?> + + escape($title); ?> + + escape(($title == '*') ? JText::_('JALL_LANGUAGE') : $title); ?> + + num_children > 0) : ?> + (num_children; ?>) + num_nodes > 0) : ?> + (num_nodes; ?>) + + escape(trim($title, '**')) == 'Language' && JLanguageMultilang::isEnabled()) : ?> + + + + state, $i, 'maps.', $canChange, 'cb'); ?> +
+ pagination->getListFooter(); ?> +
+ + + + + +
+ + diff --git a/administrator/components/com_finder/views/maps/tmpl/index.html b/administrator/components/com_finder/views/maps/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_finder/views/maps/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_finder/views/maps/view.html.php b/administrator/components/com_finder/views/maps/view.html.php new file mode 100644 index 0000000..e12f437 --- /dev/null +++ b/administrator/components/com_finder/views/maps/view.html.php @@ -0,0 +1,111 @@ +items = $this->get('Items'); + $this->total = $this->get('Total'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + FinderHelper::addSubmenu('maps'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html'); + + // Prepare the view. + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Method to configure the toolbar for this view. + * + * @return void + * + * @since 2.5 + */ + protected function addToolbar() + { + // For whatever reason, the helper isn't being found + include_once JPATH_COMPONENT . '/helpers/finder.php'; + $canDo = FinderHelper::getActions(); + + JToolbarHelper::title(JText::_('COM_FINDER_MAPS_TOOLBAR_TITLE'), 'finder'); + $toolbar = JToolbar::getInstance('toolbar'); + + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::publishList('maps.publish'); + JToolbarHelper::unpublishList('maps.unpublish'); + JToolbarHelper::divider(); + } + if ($canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'maps.delete'); + JToolbarHelper::divider(); + } + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_finder'); + } + JToolbarHelper::divider(); + $toolbar->appendButton('Popup', 'stats', 'COM_FINDER_STATISTICS', 'index.php?option=com_finder&view=statistics&tmpl=component', 550, 350); + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_COMPONENTS_FINDER_MANAGE_CONTENT_MAPS'); + + JHtmlSidebar::setAction('index.php?option=com_finder&view=maps'); + + JHtmlSidebar::addFilter( + '', + 'filter_branch', + JHtml::_('select.options', JHtml::_('finder.mapslist'), 'value', 'text', $this->state->get('filter.branch')), + true + ); + + JHtmlSidebar::addFilter( + JText::_('COM_FINDER_INDEX_FILTER_BY_STATE'), + 'filter_state', + JHtml::_('select.options', JHtml::_('finder.statelist'), 'value', 'text', $this->state->get('filter.state')) + ); + } +} diff --git a/administrator/components/com_finder/views/statistics/index.html b/administrator/components/com_finder/views/statistics/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/views/statistics/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/views/statistics/tmpl/default.php b/administrator/components/com_finder/views/statistics/tmpl/default.php new file mode 100644 index 0000000..d2236f9 --- /dev/null +++ b/administrator/components/com_finder/views/statistics/tmpl/default.php @@ -0,0 +1,52 @@ + +

+ +

+ +
+
+

data->term_count), number_format($this->data->link_count), number_format($this->data->taxonomy_node_count), number_format($this->data->taxonomy_branch_count)); ?>

+ + + + + + + + + data->type_list as $type) :?> + + + + + + + + + + +
+ + + +
+ type_title;?> + + link_count);?> +
+ + + data->link_count); ?> +
+
+
diff --git a/administrator/components/com_finder/views/statistics/tmpl/index.html b/administrator/components/com_finder/views/statistics/tmpl/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_finder/views/statistics/tmpl/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_finder/views/statistics/view.html.php b/administrator/components/com_finder/views/statistics/view.html.php new file mode 100644 index 0000000..123405b --- /dev/null +++ b/administrator/components/com_finder/views/statistics/view.html.php @@ -0,0 +1,44 @@ +data = $this->get('Data'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + parent::display($tpl); + } +} diff --git a/administrator/components/com_installer/access.xml b/administrator/components/com_installer/access.xml new file mode 100644 index 0000000..3a0f2c5 --- /dev/null +++ b/administrator/components/com_installer/access.xml @@ -0,0 +1,9 @@ + + +
+ + + + +
+
diff --git a/administrator/components/com_installer/config.xml b/administrator/components/com_installer/config.xml new file mode 100644 index 0000000..c741282 --- /dev/null +++ b/administrator/components/com_installer/config.xml @@ -0,0 +1,34 @@ + + +
+ +
+
+ + +
+
diff --git a/administrator/components/com_installer/controller.php b/administrator/components/com_installer/controller.php new file mode 100644 index 0000000..cf2044f --- /dev/null +++ b/administrator/components/com_installer/controller.php @@ -0,0 +1,66 @@ +input->get('view', 'install'); + $vFormat = $document->getType(); + $lName = $this->input->get('layout', 'default'); + + // Get and render the view. + if ($view = $this->getView($vName, $vFormat)) + { + $ftp = JClientHelper::setCredentialsFromRequest('ftp'); + $view->ftp = &$ftp; + + // Get the model for the view. + $model = $this->getModel($vName); + + // Push the model into the view (as default). + $view->setModel($model, true); + $view->setLayout($lName); + + // Push document object into the view. + $view->document = $document; + + // Load the submenu. + InstallerHelper::addSubmenu($vName); + $view->display(); + } + + return $this; + } +} diff --git a/administrator/components/com_installer/controllers/database.php b/administrator/components/com_installer/controllers/database.php new file mode 100644 index 0000000..12ceb5d --- /dev/null +++ b/administrator/components/com_installer/controllers/database.php @@ -0,0 +1,34 @@ +getModel('database'); + $model->fix(); + $this->setRedirect(JRoute::_('index.php?option=com_installer&view=database', false)); + } +} diff --git a/administrator/components/com_installer/controllers/discover.php b/administrator/components/com_installer/controllers/discover.php new file mode 100644 index 0000000..6515b0e --- /dev/null +++ b/administrator/components/com_installer/controllers/discover.php @@ -0,0 +1,62 @@ +getModel('discover'); + $model->discover(); + $this->setRedirect(JRoute::_('index.php?option=com_installer&view=discover', false)); + } + + /** + * Install a discovered extension. + * + * @return void + * + * @since 1.6 + */ + public function install() + { + $model = $this->getModel('discover'); + $model->discover_install(); + $this->setRedirect(JRoute::_('index.php?option=com_installer&view=discover', false)); + } + + /** + * Clean out the discovered extension cache. + * + * @return void + * + * @since 1.6 + */ + public function purge() + { + $model = $this->getModel('discover'); + $model->purge(); + $this->setRedirect(JRoute::_('index.php?option=com_installer&view=discover', false), $model->_message); + } +} diff --git a/administrator/components/com_installer/controllers/index.html b/administrator/components/com_installer/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/controllers/install.php b/administrator/components/com_installer/controllers/install.php new file mode 100644 index 0000000..1d8b997 --- /dev/null +++ b/administrator/components/com_installer/controllers/install.php @@ -0,0 +1,51 @@ +getModel('install'); + if ($model->install()) + { + $cache = JFactory::getCache('mod_menu'); + $cache->clean(); + // TODO: Reset the users acl here as well to kill off any missing bits + } + + $app = JFactory::getApplication(); + $redirect_url = $app->getUserState('com_installer.redirect_url'); + if (empty($redirect_url)) + { + $redirect_url = JRoute::_('index.php?option=com_installer&view=install', false); + } else + { + // wipe out the user state when we're going to redirect + $app->setUserState('com_installer.redirect_url', ''); + $app->setUserState('com_installer.message', ''); + $app->setUserState('com_installer.extension_message', ''); + } + $this->setRedirect($redirect_url); + } +} diff --git a/administrator/components/com_installer/controllers/languages.php b/administrator/components/com_installer/controllers/languages.php new file mode 100644 index 0000000..ad69687 --- /dev/null +++ b/administrator/components/com_installer/controllers/languages.php @@ -0,0 +1,97 @@ +getModel('update'); + $model->purge(); + + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Get the caching duration + $component = JComponentHelper::getComponent('com_installer'); + $params = $component->params; + $cache_timeout = $params->get('cachetimeout', 6, 'int'); + $cache_timeout = 3600 * $cache_timeout; + + // Find updates + $model = $this->getModel('languages'); + $model->findLanguages($cache_timeout); + + $this->setRedirect(JRoute::_('index.php?option=com_installer&view=languages', false)); + } + + /** + * Purge the updates list. + * + * @return void + * + * @since 2.5.7 + */ + public function purge() + { + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Purge updates + $model = $this->getModel('update'); + $model->purge(); + $model->enableSites(); + $this->setRedirect(JRoute::_('index.php?option=com_installer&view=languages', false), $model->_message); + } + + /** + * Install languages. + * + * @return void + * + * @since 2.5.7 + */ + public function install() + { + $model = $this->getModel('languages'); + + // Get array of selected languages + $lids = $this->input->get('cid', array(), 'array'); + JArrayHelper::toInteger($lids, array()); + + if (!$lids) + { + // No languages have been selected + $app = JFactory::getApplication(); + $app->enqueueMessage(JText::_('COM_INSTALLER_MSG_DISCOVER_NOEXTENSIONSELECTED')); + } + else + { + // Install selected languages + $model->install($lids); + } + + $this->setRedirect(JRoute::_('index.php?option=com_installer&view=languages', false)); + } +} diff --git a/administrator/components/com_installer/controllers/manage.php b/administrator/components/com_installer/controllers/manage.php new file mode 100644 index 0000000..c174ad5 --- /dev/null +++ b/administrator/components/com_installer/controllers/manage.php @@ -0,0 +1,126 @@ +registerTask('unpublish', 'publish'); + $this->registerTask('publish', 'publish'); + } + + /** + * Enable/Disable an extension (if supported). + * + * @return void + * + * @since 1.6 + */ + public function publish() + { + // Check for request forgeries. + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $ids = $this->input->get('cid', array(), 'array'); + $values = array('publish' => 1, 'unpublish' => 0); + $task = $this->getTask(); + $value = JArrayHelper::getValue($values, $task, 0, 'int'); + + if (empty($ids)) + { + JError::raiseWarning(500, JText::_('COM_INSTALLER_ERROR_NO_EXTENSIONS_SELECTED')); + } + else + { + // Get the model. + $model = $this->getModel('manage'); + + // Change the state of the records. + if (!$model->publish($ids, $value)) + { + JError::raiseWarning(500, implode('
', $model->getErrors())); + } + else + { + if ($value == 1) + { + $ntext = 'COM_INSTALLER_N_EXTENSIONS_PUBLISHED'; + } + elseif ($value == 0) + { + $ntext = 'COM_INSTALLER_N_EXTENSIONS_UNPUBLISHED'; + } + $this->setMessage(JText::plural($ntext, count($ids))); + } + } + + $this->setRedirect(JRoute::_('index.php?option=com_installer&view=manage', false)); + } + + /** + * Remove an extension (Uninstall). + * + * @return void + * + * @since 1.5 + */ + public function remove() + { + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $eid = $this->input->get('cid', array(), 'array'); + $model = $this->getModel('manage'); + + JArrayHelper::toInteger($eid, array()); + $model->remove($eid); + $this->setRedirect(JRoute::_('index.php?option=com_installer&view=manage', false)); + } + + /** + * Refreshes the cached metadata about an extension. + * + * Useful for debugging and testing purposes when the XML file might change. + * + * @return void + * + * @since 1.6 + */ + public function refresh() + { + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $uid = $this->input->get('cid', array(), 'array'); + $model = $this->getModel('manage'); + + JArrayHelper::toInteger($uid, array()); + $model->refresh($uid); + $this->setRedirect(JRoute::_('index.php?option=com_installer&view=manage', false)); + } +} diff --git a/administrator/components/com_installer/controllers/update.php b/administrator/components/com_installer/controllers/update.php new file mode 100644 index 0000000..6f69a52 --- /dev/null +++ b/administrator/components/com_installer/controllers/update.php @@ -0,0 +1,155 @@ +getModel('update'); + $uid = $this->input->get('cid', array(), 'array'); + + JArrayHelper::toInteger($uid, array()); + if ($model->update($uid)) + { + $cache = JFactory::getCache('mod_menu'); + $cache->clean(); + } + + $app = JFactory::getApplication(); + $redirect_url = $app->getUserState('com_installer.redirect_url'); + if (empty($redirect_url)) + { + $redirect_url = JRoute::_('index.php?option=com_installer&view=update', false); + } + else + { + // Wipe out the user state when we're going to redirect + $app->setUserState('com_installer.redirect_url', ''); + $app->setUserState('com_installer.message', ''); + $app->setUserState('com_installer.extension_message', ''); + } + $this->setRedirect($redirect_url); + } + + /** + * Find new updates. + * + * @return void + * + * @since 1.6 + */ + public function find() + { + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Get the caching duration + $component = JComponentHelper::getComponent('com_installer'); + $params = $component->params; + $cache_timeout = $params->get('cachetimeout', 6, 'int'); + $cache_timeout = 3600 * $cache_timeout; + + // Find updates + $model = $this->getModel('update'); + $model->findUpdates(0, $cache_timeout); + $this->setRedirect(JRoute::_('index.php?option=com_installer&view=update', false)); + } + + /** + * Purges updates. + * + * @return void + * + * @since 1.6 + */ + public function purge() + { + // Purge updates + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + $model = $this->getModel('update'); + $model->purge(); + $model->enableSites(); + $this->setRedirect(JRoute::_('index.php?option=com_installer&view=update', false), $model->_message); + } + + /** + * Fetch and report updates in JSON format, for AJAX requests + * + * @return void + * + * @since 2.5 + */ + public function ajax() + { + /* + * Note: we don't do a token check as we're fetching information + * asynchronously. This means that between requests the token might + * change, making it impossible for AJAX to work. + */ + + $eid = $this->input->getInt('eid', 0); + $skip = $this->input->get('skip', array(), 'array'); + + $cache_timeout = $this->input->getInt('cache_timeout', 0); + if ($cache_timeout == 0) + { + $component = JComponentHelper::getComponent('com_installer'); + $params = $component->params; + $cache_timeout = $params->get('cachetimeout', 6, 'int'); + $cache_timeout = 3600 * $cache_timeout; + } + + $model = $this->getModel('update'); + $model->findUpdates($eid, $cache_timeout); + + $model->setState('list.start', 0); + $model->setState('list.limit', 0); + if ($eid != 0) + { + $model->setState('filter.extension_id', $eid); + } + $updates = $model->getItems(); + + if (!empty($skip)) + { + $unfiltered_updates = $updates; + $updates = array(); + foreach ($unfiltered_updates as $update) + { + if (!in_array($update->extension_id, $skip)) + { + $updates[] = $update; + } + } + } + echo json_encode($updates); + + JFactory::getApplication()->close(); + } +} diff --git a/administrator/components/com_installer/helpers/html/index.html b/administrator/components/com_installer/helpers/html/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/helpers/html/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/helpers/html/manage.php b/administrator/components/com_installer/helpers/html/manage.php new file mode 100644 index 0000000..d9d770e --- /dev/null +++ b/administrator/components/com_installer/helpers/html/manage.php @@ -0,0 +1,67 @@ + array( + '', + 'COM_INSTALLER_EXTENSION_PROTECTED', + '', + 'COM_INSTALLER_EXTENSION_PROTECTED', + true, + 'protected', + 'protected' + ), + 1 => array( + 'unpublish', + 'COM_INSTALLER_EXTENSION_ENABLED', + 'COM_INSTALLER_EXTENSION_DISABLE', + 'COM_INSTALLER_EXTENSION_ENABLED', + true, + 'publish', + 'publish' + ), + 0 => array( + 'publish', + 'COM_INSTALLER_EXTENSION_DISABLED', + 'COM_INSTALLER_EXTENSION_ENABLE', + 'COM_INSTALLER_EXTENSION_DISABLED', + true, + 'unpublish', + 'unpublish' + ), + ); + + return JHtml::_('jgrid.state', $states, $value, $i, 'manage.', $enabled, true, $checkbox); + } +} diff --git a/administrator/components/com_installer/helpers/index.html b/administrator/components/com_installer/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/helpers/installer.php b/administrator/components/com_installer/helpers/installer.php new file mode 100644 index 0000000..5d2fbf1 --- /dev/null +++ b/administrator/components/com_installer/helpers/installer.php @@ -0,0 +1,142 @@ +getQuery(true) + ->select('DISTINCT type') + ->from('#__extensions'); + $db->setQuery($query); + $types = $db->loadColumn(); + + $options = array(); + foreach ($types as $type) + { + $options[] = JHtml::_('select.option', $type, 'COM_INSTALLER_TYPE_' . strtoupper($type)); + } + + return $options; + } + + /** + * Get a list of filter options for the extension types. + * + * @return array An array of stdClass objects. + * + * @since 3.0 + */ + public static function getExtensionGroupes() + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('DISTINCT folder') + ->from('#__extensions') + ->where('folder != ' . $db->quote('')) + ->order('folder'); + $db->setQuery($query); + $folders = $db->loadColumn(); + + $options = array(); + foreach ($folders as $folder) + { + $options[] = JHtml::_('select.option', $folder, $folder); + } + + return $options; + } + + /** + * Gets a list of the actions that can be performed. + * + * @return JObject + * + * @since 1.6 + */ + public static function getActions() + { + $user = JFactory::getUser(); + $result = new JObject; + + $assetName = 'com_installer'; + + $actions = JAccess::getActions($assetName); + + foreach ($actions as $action) + { + $result->set($action->name, $user->authorise($action->name, $assetName)); + } + + return $result; + } +} diff --git a/administrator/components/com_installer/index.html b/administrator/components/com_installer/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/installer.php b/administrator/components/com_installer/installer.php new file mode 100644 index 0000000..2a4a882 --- /dev/null +++ b/administrator/components/com_installer/installer.php @@ -0,0 +1,19 @@ +authorise('core.manage', 'com_installer')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$controller = JControllerLegacy::getInstance('Installer'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_installer/installer.xml b/administrator/components/com_installer/installer.xml new file mode 100644 index 0000000..16eea9a --- /dev/null +++ b/administrator/components/com_installer/installer.xml @@ -0,0 +1,29 @@ + + + com_installer + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_INSTALLER_XML_DESCRIPTION + + + config.xml + controller.php + index.html + installer.php + controllers + helpers + models + views + + + language/en-GB.com_installer.ini + language/en-GB.com_installer.sys.ini + + + + diff --git a/administrator/components/com_installer/models/database.php b/administrator/components/com_installer/models/database.php new file mode 100644 index 0000000..03eadfa --- /dev/null +++ b/administrator/components/com_installer/models/database.php @@ -0,0 +1,247 @@ +setState('message', $app->getUserState('com_installer.message')); + $this->setState('extension_message', $app->getUserState('com_installer.extension_message')); + $app->setUserState('com_installer.message', ''); + $app->setUserState('com_installer.extension_message', ''); + parent::populateState('name', 'asc'); + } + + /** + * Fixes database problems + * + * @return void + */ + public function fix() + { + if (!$changeSet = $this->getItems()) + { + return false; + } + $changeSet->fix(); + $this->fixSchemaVersion($changeSet); + $this->fixUpdateVersion(); + $installer = new JoomlaInstallerScript; + $installer->deleteUnexistingFiles(); + $this->fixDefaultTextFilters(); + } + + /** + * Gets the changeset object + * + * @return JSchemaChangeset + */ + public function getItems() + { + $folder = JPATH_ADMINISTRATOR . '/components/com_admin/sql/updates/'; + + try + { + $changeSet = JSchemaChangeset::getInstance(JFactory::getDbo(), $folder); + } + catch (RuntimeException $e) + { + JFactory::getApplication()->enqueueMessage($e->getMessage(), 'warning'); + return false; + } + return $changeSet; + } + + /** + * Method to get a JPagination object for the data set. + * + * @return boolean + * + * @since 12.2 + */ + public function getPagination() + { + return true; + } + + /** + * Get version from #__schemas table + * + * @return mixed the return value from the query, or null if the query fails + * + * @throws Exception + */ + public function getSchemaVersion() + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('version_id') + ->from($db->quoteName('#__schemas')) + ->where('extension_id = 700'); + $db->setQuery($query); + $result = $db->loadResult(); + + return $result; + } + + /** + * Fix schema version if wrong + * + * @param JSchemaChangeSet $changeSet Schema change set + * + * @return mixed string schema version if success, false if fail + */ + public function fixSchemaVersion($changeSet) + { + // Get correct schema version -- last file in array + $schema = $changeSet->getSchema(); + $db = JFactory::getDbo(); + $result = false; + + // Check value. If ok, don't do update + $version = $this->getSchemaVersion(); + if ($version == $schema) + { + $result = $version; + } + else + { + // Delete old row + $query = $db->getQuery(true) + ->delete($db->quoteName('#__schemas')) + ->where($db->quoteName('extension_id') . ' = 700'); + $db->setQuery($query); + $db->execute(); + + // Add new row + $query->clear() + ->insert($db->quoteName('#__schemas')) + ->set($db->quoteName('extension_id') . '= 700') + ->set($db->quoteName('version_id') . '= ' . $db->quote($schema)); + $db->setQuery($query); + if ($db->execute()) + { + $result = $schema; + } + } + return $result; + } + + /** + * Get current version from #__extensions table + * + * @return mixed version if successful, false if fail + */ + + public function getUpdateVersion() + { + $table = JTable::getInstance('Extension'); + $table->load('700'); + $cache = new JRegistry($table->manifest_cache); + return $cache->get('version'); + } + + /** + * Fix Joomla version in #__extensions table if wrong (doesn't equal JVersion short version) + * + * @return mixed string update version if success, false if fail + */ + public function fixUpdateVersion() + { + $table = JTable::getInstance('Extension'); + $table->load('700'); + $cache = new JRegistry($table->manifest_cache); + $updateVersion = $cache->get('version'); + $cmsVersion = new JVersion; + if ($updateVersion == $cmsVersion->getShortVersion()) + { + return $updateVersion; + } + else + { + $cache->set('version', $cmsVersion->getShortVersion()); + $table->manifest_cache = $cache->toString(); + if ($table->store()) + { + return $cmsVersion->getShortVersion(); + } + else + { + return false; + } + + } + } + + /** + * For version 2.5.x only + * Check if com_config parameters are blank. + * + * @return string default text filters (if any) + */ + public function getDefaultTextFilters() + { + $table = JTable::getInstance('Extension'); + $table->load($table->find(array('name' => 'com_config'))); + return $table->params; + } + /** + * For version 2.5.x only + * Check if com_config parameters are blank. If so, populate with com_content text filters. + * + * @return mixed boolean true if params are updated, null otherwise + */ + public function fixDefaultTextFilters() + { + $table = JTable::getInstance('Extension'); + $table->load($table->find(array('name' => 'com_config'))); + + // Check for empty $config and non-empty content filters + if (!$table->params) + { + // Get filters from com_content and store if you find them + $contentParams = JComponentHelper::getParams('com_content'); + if ($contentParams->get('filters')) + { + $newParams = new JRegistry; + $newParams->set('filters', $contentParams->get('filters')); + $table->params = (string) $newParams; + $table->store(); + return true; + } + } + } +} diff --git a/administrator/components/com_installer/models/discover.php b/administrator/components/com_installer/models/discover.php new file mode 100644 index 0000000..ec6b728 --- /dev/null +++ b/administrator/components/com_installer/models/discover.php @@ -0,0 +1,180 @@ +setState('message', $app->getUserState('com_installer.message')); + $this->setState('extension_message', $app->getUserState('com_installer.extension_message')); + $app->setUserState('com_installer.message', ''); + $app->setUserState('com_installer.extension_message', ''); + parent::populateState('name', 'asc'); + } + + /** + * Method to get the database query. + * + * @return JDatabaseQuery the database query + * + * @since 1.6 + */ + protected function getListQuery() + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('*') + ->from('#__extensions') + ->where('state=-1'); + return $query; + } + + /** + * Discover extensions. + * + * Finds uninstalled extensions + * + * @return void + * + * @since 1.6 + */ + public function discover() + { + // Purge the list of discovered extensions + $this->purge(); + + $installer = JInstaller::getInstance(); + $results = $installer->discover(); + + // Get all templates, including discovered ones + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('extension_id, element, folder, client_id, type') + ->from('#__extensions'); + + $db->setQuery($query); + $installedtmp = $db->loadObjectList(); + $extensions = array(); + + foreach ($installedtmp as $install) + { + $key = implode(':', array($install->type, $install->element, $install->folder, $install->client_id)); + $extensions[$key] = $install; + } + unset($installedtmp); + + foreach ($results as $result) + { + // Check if we have a match on the element + $key = implode(':', array($result->type, $result->element, $result->folder, $result->client_id)); + if (!array_key_exists($key, $extensions)) + { + // Put it into the table + $result->store(); + } + } + } + + /** + * Installs a discovered extension. + * + * @return void + * + * @since 1.6 + */ + public function discover_install() + { + $app = JFactory::getApplication(); + $installer = JInstaller::getInstance(); + $eid = JRequest::getVar('cid', 0); + if (is_array($eid) || $eid) + { + if (!is_array($eid)) + { + $eid = array($eid); + } + JArrayHelper::toInteger($eid); + $app = JFactory::getApplication(); + $failed = false; + foreach ($eid as $id) + { + $result = $installer->discover_install($id); + if (!$result) + { + $failed = true; + $app->enqueueMessage(JText::_('COM_INSTALLER_MSG_DISCOVER_INSTALLFAILED') . ': ' . $id); + } + } + $this->setState('action', 'remove'); + $this->setState('name', $installer->get('name')); + $app->setUserState('com_installer.message', $installer->message); + $app->setUserState('com_installer.extension_message', $installer->get('extension_message')); + if (!$failed) + { + $app->enqueueMessage(JText::_('COM_INSTALLER_MSG_DISCOVER_INSTALLSUCCESSFUL')); + } + } + else + { + $app->enqueueMessage(JText::_('COM_INSTALLER_MSG_DISCOVER_NOEXTENSIONSELECTED')); + } + } + + /** + * Cleans out the list of discovered extensions. + * + * @return bool True on success + * + * @since 1.6 + */ + public function purge() + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->delete('#__extensions') + ->where('state = -1'); + $db->setQuery($query); + if ($db->execute()) + { + $this->_message = JText::_('COM_INSTALLER_MSG_DISCOVER_PURGEDDISCOVEREDEXTENSIONS'); + return true; + } + else + { + $this->_message = JText::_('COM_INSTALLER_MSG_DISCOVER_FAILEDTOPURGEEXTENSIONS'); + return false; + } + } +} diff --git a/administrator/components/com_installer/models/extension.php b/administrator/components/com_installer/models/extension.php new file mode 100644 index 0000000..ba2d01e --- /dev/null +++ b/administrator/components/com_installer/models/extension.php @@ -0,0 +1,191 @@ +getState('list.ordering'); + $search = $this->getState('filter.search'); + + // Replace slashes so preg_match will work + $search = str_replace('/', ' ', $search); + $db = $this->getDbo(); + + if ($ordering == 'name' || (!empty($search) && stripos($search, 'id:') !== 0)) + { + $db->setQuery($query); + $result = $db->loadObjectList(); + $this->translate($result); + if (!empty($search)) + { + foreach ($result as $i => $item) + { + if (!preg_match("/$search/i", $item->name)) + { + unset($result[$i]); + } + } + } + JArrayHelper::sortObjects($result, $this->getState('list.ordering'), $this->getState('list.direction') == 'desc' ? -1 : 1, true, true); + $total = count($result); + $this->cache[$this->getStoreId('getTotal')] = $total; + if ($total < $limitstart) + { + $limitstart = 0; + $this->setState('list.start', 0); + } + return array_slice($result, $limitstart, $limit ? $limit : null); + } + else + { + $query->order($db->quoteName($ordering) . ' ' . $this->getState('list.direction')); + $result = parent::_getList($query, $limitstart, $limit); + $this->translate($result); + return $result; + } + } + + /** + * Translate a list of objects + * + * @param array &$items The array of objects + * + * @return array The array of translated objects + */ + private function translate(&$items) + { + $lang = JFactory::getLanguage(); + foreach ($items as &$item) + { + if (strlen($item->manifest_cache)) + { + $data = json_decode($item->manifest_cache); + if ($data) + { + foreach ($data as $key => $value) + { + if ($key == 'type') + { + // Ignore the type field + continue; + } + $item->$key = $value; + } + } + } + $item->author_info = @$item->authorEmail . '
' . @$item->authorUrl; + $item->client = $item->client_id ? JText::_('JADMINISTRATOR') : JText::_('JSITE'); + $path = $item->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE; + switch ($item->type) + { + case 'component': + $extension = $item->element; + $source = JPATH_ADMINISTRATOR . '/components/' . $extension; + $lang->load("$extension.sys", JPATH_ADMINISTRATOR, null, false, false) + || $lang->load("$extension.sys", $source, null, false, false) + || $lang->load("$extension.sys", JPATH_ADMINISTRATOR, $lang->getDefault(), false, false) + || $lang->load("$extension.sys", $source, $lang->getDefault(), false, false); + break; + case 'file': + $extension = 'files_' . $item->element; + $lang->load("$extension.sys", JPATH_SITE, null, false, false) + || $lang->load("$extension.sys", JPATH_SITE, $lang->getDefault(), false, false); + break; + case 'library': + $extension = 'lib_' . $item->element; + $lang->load("$extension.sys", JPATH_SITE, null, false, false) + || $lang->load("$extension.sys", JPATH_SITE, $lang->getDefault(), false, false); + break; + case 'module': + $extension = $item->element; + $source = $path . '/modules/' . $extension; + $lang->load("$extension.sys", $path, null, false, false) + || $lang->load("$extension.sys", $source, null, false, false) + || $lang->load("$extension.sys", $path, $lang->getDefault(), false, false) + || $lang->load("$extension.sys", $source, $lang->getDefault(), false, false); + break; + case 'package': + $extension = $item->element; + $lang->load("$extension.sys", JPATH_SITE, null, false, false) + || $lang->load("$extension.sys", JPATH_SITE, $lang->getDefault(), false, false); + break; + case 'plugin': + $extension = 'plg_' . $item->folder . '_' . $item->element; + $source = JPATH_PLUGINS . '/' . $item->folder . '/' . $item->element; + $lang->load("$extension.sys", JPATH_ADMINISTRATOR, null, false, false) + || $lang->load("$extension.sys", $source, null, false, false) + || $lang->load("$extension.sys", JPATH_ADMINISTRATOR, $lang->getDefault(), false, false) + || $lang->load("$extension.sys", $source, $lang->getDefault(), false, false); + break; + case 'template': + $extension = 'tpl_' . $item->element; + $source = $path . '/templates/' . $item->element; + $lang->load("$extension.sys", $path, null, false, false) + || $lang->load("$extension.sys", $source, null, false, false) + || $lang->load("$extension.sys", $path, $lang->getDefault(), false, false) + || $lang->load("$extension.sys", $source, $lang->getDefault(), false, false); + break; + } + if (!in_array($item->type, array('language', 'template', 'library'))) + { + $item->name = JText::_($item->name); + } + settype($item->description, 'string'); + if (!in_array($item->type, array('language'))) + { + $item->description = JText::_($item->description); + } + } + } +} diff --git a/administrator/components/com_installer/models/index.html b/administrator/components/com_installer/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/models/install.php b/administrator/components/com_installer/models/install.php new file mode 100644 index 0000000..154a306 --- /dev/null +++ b/administrator/components/com_installer/models/install.php @@ -0,0 +1,276 @@ +setState('message', $app->getUserState('com_installer.message')); + $this->setState('extension_message', $app->getUserState('com_installer.extension_message')); + $app->setUserState('com_installer.message', ''); + $app->setUserState('com_installer.extension_message', ''); + + // Recall the 'Install from Directory' path. + $path = $app->getUserStateFromRequest($this->_context . '.install_directory', 'install_directory', $app->getCfg('tmp_path')); + $this->setState('install.directory', $path); + parent::populateState(); + } + + /** + * Install an extension from either folder, url or upload. + * + * @return boolean result of install + * + * @since 1.5 + */ + public function install() + { + $this->setState('action', 'install'); + + // Set FTP credentials, if given. + JClientHelper::setCredentialsFromRequest('ftp'); + $app = JFactory::getApplication(); + + switch ($app->input->getWord('installtype')) + { + case 'folder': + // Remember the 'Install from Directory' path. + $app->getUserStateFromRequest($this->_context . '.install_directory', 'install_directory'); + $package = $this->_getPackageFromFolder(); + break; + + case 'upload': + $package = $this->_getPackageFromUpload(); + break; + + case 'url': + $package = $this->_getPackageFromUrl(); + break; + + default: + $app->setUserState('com_installer.message', JText::_('COM_INSTALLER_NO_INSTALL_TYPE_FOUND')); + return false; + break; + } + + // Was the package unpacked? + if (!$package) + { + $app->setUserState('com_installer.message', JText::_('COM_INSTALLER_UNABLE_TO_FIND_INSTALL_PACKAGE')); + return false; + } + + // Get an installer instance + $installer = JInstaller::getInstance(); + + // Install the package + if (!$installer->install($package['dir'])) + { + // There was an error installing the package + $msg = JText::sprintf('COM_INSTALLER_INSTALL_ERROR', JText::_('COM_INSTALLER_TYPE_TYPE_' . strtoupper($package['type']))); + $result = false; + } + else + { + // Package installed sucessfully + $msg = JText::sprintf('COM_INSTALLER_INSTALL_SUCCESS', JText::_('COM_INSTALLER_TYPE_TYPE_' . strtoupper($package['type']))); + $result = true; + } + + // Set some model state values + $app = JFactory::getApplication(); + $app->enqueueMessage($msg); + $this->setState('name', $installer->get('name')); + $this->setState('result', $result); + $app->setUserState('com_installer.message', $installer->message); + $app->setUserState('com_installer.extension_message', $installer->get('extension_message')); + $app->setUserState('com_installer.redirect_url', $installer->get('redirect_url')); + + // Cleanup the install files + if (!is_file($package['packagefile'])) + { + $config = JFactory::getConfig(); + $package['packagefile'] = $config->get('tmp_path') . '/' . $package['packagefile']; + } + + JInstallerHelper::cleanupInstall($package['packagefile'], $package['extractdir']); + + return $result; + } + + /** + * Works out an installation package from a HTTP upload + * + * @return package definition or false on failure + */ + protected function _getPackageFromUpload() + { + // Get the uploaded file information + $userfile = JRequest::getVar('install_package', null, 'files', 'array'); + + // Make sure that file uploads are enabled in php + if (!(bool) ini_get('file_uploads')) + { + JError::raiseWarning('', JText::_('COM_INSTALLER_MSG_INSTALL_WARNINSTALLFILE')); + return false; + } + + // Make sure that zlib is loaded so that the package can be unpacked + if (!extension_loaded('zlib')) + { + JError::raiseWarning('', JText::_('COM_INSTALLER_MSG_INSTALL_WARNINSTALLZLIB')); + return false; + } + + // If there is no uploaded file, we have a problem... + if (!is_array($userfile)) + { + JError::raiseWarning('', JText::_('COM_INSTALLER_MSG_INSTALL_NO_FILE_SELECTED')); + return false; + } + + // Check if there was a problem uploading the file. + if ($userfile['error'] || $userfile['size'] < 1) + { + JError::raiseWarning('', JText::_('COM_INSTALLER_MSG_INSTALL_WARNINSTALLUPLOADERROR')); + return false; + } + + // Build the appropriate paths + $config = JFactory::getConfig(); + $tmp_dest = $config->get('tmp_path') . '/' . $userfile['name']; + $tmp_src = $userfile['tmp_name']; + + // Move uploaded file + jimport('joomla.filesystem.file'); + JFile::upload($tmp_src, $tmp_dest); + + // Unpack the downloaded package file + $package = JInstallerHelper::unpack($tmp_dest); + + return $package; + } + + /** + * Install an extension from a directory + * + * @return array Package details or false on failure + * + * @since 1.5 + */ + protected function _getPackageFromFolder() + { + $input = JFactory::getApplication()->input; + + // Get the path to the package to install + $p_dir = $input->getString('install_directory'); + $p_dir = JPath::clean($p_dir); + + // Did you give us a valid directory? + if (!is_dir($p_dir)) + { + JError::raiseWarning('', JText::_('COM_INSTALLER_MSG_INSTALL_PLEASE_ENTER_A_PACKAGE_DIRECTORY')); + return false; + } + + // Detect the package type + $type = JInstallerHelper::detectType($p_dir); + + // Did you give us a valid package? + if (!$type) + { + JError::raiseWarning('', JText::_('COM_INSTALLER_MSG_INSTALL_PATH_DOES_NOT_HAVE_A_VALID_PACKAGE')); + return false; + } + + $package['packagefile'] = null; + $package['extractdir'] = null; + $package['dir'] = $p_dir; + $package['type'] = $type; + + return $package; + } + + /** + * Install an extension from a URL + * + * @return Package details or false on failure + * + * @since 1.5 + */ + protected function _getPackageFromUrl() + { + $input = JFactory::getApplication()->input; + + // Get the URL of the package to install + $url = $input->getString('install_url'); + + // Did you give us a URL? + if (!$url) + { + JError::raiseWarning('', JText::_('COM_INSTALLER_MSG_INSTALL_ENTER_A_URL')); + return false; + } + + // Download the package at the URL given + $p_file = JInstallerHelper::downloadPackage($url); + + // Was the package downloaded? + if (!$p_file) + { + JError::raiseWarning('', JText::_('COM_INSTALLER_MSG_INSTALL_INVALID_URL')); + return false; + } + + $config = JFactory::getConfig(); + $tmp_dest = $config->get('tmp_path'); + + // Unpack the downloaded package file + $package = JInstallerHelper::unpack($tmp_dest . '/' . $p_file); + + return $package; + } +} diff --git a/administrator/components/com_installer/models/languages.php b/administrator/components/com_installer/models/languages.php new file mode 100644 index 0000000..30d72ec --- /dev/null +++ b/administrator/components/com_installer/models/languages.php @@ -0,0 +1,278 @@ +getQuery(true); + + // Select the required fields from the updates table + $query->select('update_id, name, version, detailsurl, type') + + ->from('#__updates'); + + // This Where clause will avoid to list languages already installed. + $query->where('extension_id = 0'); + + // Filter by search in title + $search = $this->getState('filter.search'); + if (!empty($search)) + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('(name LIKE ' . $search . ')'); + } + + // Add the list ordering clause. + $listOrder = $this->state->get('list.ordering'); + $orderDirn = $this->state->get('list.direction'); + $query->order($db->escape($listOrder) . ' ' . $db->escape($orderDirn)); + + return $query; + } + + /** + * Method to get a store id based on model configuration state. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + * + * @since 2.5.7 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + + return parent::getStoreId($id); + } + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @param string $ordering list order + * @param string $direction direction in the list + * + * @return void + * + * @since 2.5.7 + */ + protected function populateState($ordering = 'name', $direction = 'asc') + { + $app = JFactory::getApplication(); + + $value = $app->getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $value); + + $this->setState('extension_message', $app->getUserState('com_installer.extension_message')); + + parent::populateState($ordering, $direction); + } + + /** + * Method to find available languages in the Accredited Languages Update Site. + * + * @param int $cache_timeout time before refreshing the cached updates + * + * @return bool + * + * @since 2.5.7 + */ + public function findLanguages($cache_timeout = 0) + { + $updater = JUpdater::getInstance(); + + /* + * The following function uses extension_id 600, that is the english language extension id. + * In #__update_sites_extensions you should have 600 linked to the Accredited Translations Repo + */ + $updater->findUpdates(array(600), $cache_timeout); + + return true; + } + + /** + * Install languages in the system. + * + * @param array $lids array of language ids selected in the list + * + * @return bool + * + * @since 2.5.7 + */ + public function install($lids) + { + $app = JFactory::getApplication(); + $installer = JInstaller::getInstance(); + + // Loop through every selected language + foreach ($lids as $id) + { + // Loads the update database object that represents the language + $language = JTable::getInstance('update'); + $language->load($id); + + // Get the url to the XML manifest file of the selected language + $remote_manifest = $this->_getLanguageManifest($id); + if (!$remote_manifest) + { + // Could not find the url, the information in the update server may be corrupt + $message = JText::sprintf('COM_INSTALLER_MSG_LANGUAGES_CANT_FIND_REMOTE_MANIFEST', $language->name); + $message .= ' ' . JText::_('COM_INSTALLER_MSG_LANGUAGES_TRY_LATER'); + $app->enqueueMessage($message); + continue; + } + + // Based on the language XML manifest get the url of the package to download + $package_url = $this->_getPackageUrl($remote_manifest); + if (!$package_url) + { + // Could not find the url , maybe the url is wrong in the update server, or there is not internet access + $message = JText::sprintf('COM_INSTALLER_MSG_LANGUAGES_CANT_FIND_REMOTE_PACKAGE', $language->name); + $message .= ' ' . JText::_('COM_INSTALLER_MSG_LANGUAGES_TRY_LATER'); + $app->enqueueMessage($message); + continue; + } + + // Download the package to the tmp folder + $package = $this->_downloadPackage($package_url); + + // Install the package + if (!$installer->install($package['dir'])) + { + // There was an error installing the package + $message = JText::sprintf('COM_INSTALLER_INSTALL_ERROR', $language->name); + $message .= ' ' . JText::_('COM_INSTALLER_MSG_LANGUAGES_TRY_LATER'); + $app->enqueueMessage($message); + continue; + } + + // Package installed successfully + $app->enqueueMessage(JText::sprintf('COM_INSTALLER_INSTALL_SUCCESS', $language->name)); + + // Cleanup the install files in tmp folder + if (!is_file($package['packagefile'])) + { + $config = JFactory::getConfig(); + $package['packagefile'] = $config->get('tmp_path') . '/' . $package['packagefile']; + } + JInstallerHelper::cleanupInstall($package['packagefile'], $package['extractdir']); + + // Delete the installed language from the list + $language->delete($id); + } + + } + + /** + * Gets the manifest file of a selected language from a the language list in a update server. + * + * @param int $uid the id of the language in the #__updates table + * + * @return string + * + * @since 2.5.7 + */ + protected function _getLanguageManifest($uid) + { + $instance = JTable::getInstance('update'); + $instance->load($uid); + + return $instance->detailsurl; + } + + /** + * Finds the url of the package to download. + * + * @param string $remote_manifest url to the manifest XML file of the remote package + * + * @return string|bool + * + * @since 2.5.7 + */ + protected function _getPackageUrl( $remote_manifest ) + { + $update = new JUpdate; + $update->loadFromXML($remote_manifest); + $package_url = trim($update->get('downloadurl', false)->_data); + + return $package_url; + } + + /** + * Download a language package from a URL and unpack it in the tmp folder. + * + * @param string $url hola + * + * @return array|bool Package details or false on failure + * + * @since 2.5.7 + */ + protected function _downloadPackage($url) + { + // Download the package from the given URL + $p_file = JInstallerHelper::downloadPackage($url); + + // Was the package downloaded? + if (!$p_file) + { + JError::raiseWarning('', JText::_('COM_INSTALLER_MSG_INSTALL_INVALID_URL')); + return false; + } + + $config = JFactory::getConfig(); + $tmp_dest = $config->get('tmp_path'); + + // Unpack the downloaded package file + $package = JInstallerHelper::unpack($tmp_dest . '/' . $p_file); + + return $package; + } +} diff --git a/administrator/components/com_installer/models/manage.php b/administrator/components/com_installer/models/manage.php new file mode 100644 index 0000000..9977db0 --- /dev/null +++ b/administrator/components/com_installer/models/manage.php @@ -0,0 +1,329 @@ +getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $clientId = $this->getUserStateFromRequest($this->context . '.filter.client_id', 'filter_client_id', ''); + $this->setState('filter.client_id', $clientId); + + $status = $this->getUserStateFromRequest($this->context . '.filter.status', 'filter_status', ''); + $this->setState('filter.status', $status); + + $categoryId = $this->getUserStateFromRequest($this->context . '.filter.type', 'filter_type', ''); + $this->setState('filter.type', $categoryId); + + $group = $this->getUserStateFromRequest($this->context . '.filter.group', 'filter_group', ''); + $this->setState('filter.group', $group); + + $this->setState('message', $app->getUserState('com_installer.message')); + $this->setState('extension_message', $app->getUserState('com_installer.extension_message')); + $app->setUserState('com_installer.message', ''); + $app->setUserState('com_installer.extension_message', ''); + + parent::populateState('name', 'asc'); + } + + /** + * Enable/Disable an extension. + * + * @param array &$eid Extension ids to un/publish + * @param int $value Publish value + * + * @return boolean True on success + * + * @since 1.5 + */ + public function publish(&$eid = array(), $value = 1) + { + $user = JFactory::getUser(); + if ($user->authorise('core.edit.state', 'com_installer')) + { + $result = true; + + /* + * Ensure eid is an array of extension ids + * TODO: If it isn't an array do we want to set an error and fail? + */ + if (!is_array($eid)) + { + $eid = array($eid); + } + + // Get a table object for the extension type + $table = JTable::getInstance('Extension'); + JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_templates/tables'); + + // Enable the extension in the table and store it in the database + foreach ($eid as $i => $id) + { + $table->load($id); + if ($table->type == 'template') + { + $style = JTable::getInstance('Style', 'TemplatesTable'); + if ($style->load(array('template' => $table->element, 'client_id' => $table->client_id, 'home' => 1))) + { + JError::raiseNotice(403, JText::_('COM_INSTALLER_ERROR_DISABLE_DEFAULT_TEMPLATE_NOT_PERMITTED')); + unset($eid[$i]); + continue; + } + } + if ($table->protected == 1) + { + $result = false; + JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED')); + } + else + { + $table->enabled = $value; + } + if (!$table->store()) + { + $this->setError($table->getError()); + $result = false; + } + } + } + else + { + $result = false; + JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED')); + } + return $result; + } + + /** + * Refreshes the cached manifest information for an extension. + * + * @param int $eid extension identifier (key in #__extensions) + * + * @return boolean result of refresh + * + * @since 1.6 + */ + public function refresh($eid) + { + if (!is_array($eid)) + { + $eid = array($eid => 0); + } + + // Get an installer object for the extension type + $installer = JInstaller::getInstance(); + $result = 0; + + // Uninstall the chosen extensions + foreach ($eid as $id) + { + $result |= $installer->refreshManifestCache($id); + } + return $result; + } + + /** + * Remove (uninstall) an extension + * + * @param array $eid An array of identifiers + * + * @return boolean True on success + * + * @since 1.5 + */ + public function remove($eid = array()) + { + $user = JFactory::getUser(); + if ($user->authorise('core.delete', 'com_installer')) + { + + $failed = array(); + + /* + * Ensure eid is an array of extension ids in the form id => client_id + * TODO: If it isn't an array do we want to set an error and fail? + */ + if (!is_array($eid)) + { + $eid = array($eid => 0); + } + + // Get an installer object for the extension type + $installer = JInstaller::getInstance(); + $row = JTable::getInstance('extension'); + + // Uninstall the chosen extensions + foreach ($eid as $id) + { + $id = trim($id); + $row->load($id); + if ($row->type && $row->type != 'language') + { + $result = $installer->uninstall($row->type, $id); + + // Build an array of extensions that failed to uninstall + if ($result === false) + { + $failed[] = $id; + } + } + else + { + $failed[] = $id; + } + } + + $langstring = 'COM_INSTALLER_TYPE_TYPE_' . strtoupper($row->type); + $rowtype = JText::_($langstring); + if (strpos($rowtype, $langstring) !== false) + { + $rowtype = $row->type; + } + + if (count($failed)) + { + if ($row->type == 'language') + { + + // One should always uninstall a language package, not a single language + $msg = JText::_('COM_INSTALLER_UNINSTALL_LANGUAGE'); + $result = false; + } + else + { + + // There was an error in uninstalling the package + $msg = JText::sprintf('COM_INSTALLER_UNINSTALL_ERROR', $rowtype); + $result = false; + } + } + else + { + + // Package uninstalled sucessfully + $msg = JText::sprintf('COM_INSTALLER_UNINSTALL_SUCCESS', $rowtype); + $result = true; + } + $app = JFactory::getApplication(); + $app->enqueueMessage($msg); + $this->setState('action', 'remove'); + $this->setState('name', $installer->get('name')); + $app->setUserState('com_installer.message', $installer->message); + $app->setUserState('com_installer.extension_message', $installer->get('extension_message')); + return $result; + } + else + { + JError::raiseWarning(403, JText::_('JERROR_CORE_DELETE_NOT_PERMITTED')); + } + } + + /** + * Method to get the database query + * + * @return JDatabaseQuery The database query + * + * @since 1.6 + */ + protected function getListQuery() + { + $status = $this->getState('filter.status'); + $type = $this->getState('filter.type'); + $client = $this->getState('filter.client_id'); + $group = $this->getState('filter.group'); + $query = JFactory::getDbo()->getQuery(true) + ->select('*') + ->select('2*protected+(1-protected)*enabled as status') + ->from('#__extensions') + ->where('state=0'); + if ($status != '') + { + if ($status == '2') + { + $query->where('protected = 1'); + } + elseif ($status == '3') + { + $query->where('protected = 0'); + } + else + { + $query->where('protected = 0') + ->where('enabled=' . (int) $status); + } + } + if ($type) + { + $query->where('type=' . $this->_db->quote($type)); + } + if ($client != '') + { + $query->where('client_id=' . (int) $client); + } + if ($group != '' && in_array($type, array('plugin', 'library', ''))) + { + $query->where('folder=' . $this->_db->quote($group == '*' ? '' : $group)); + } + + // Filter by search in id + $search = $this->getState('filter.search'); + if (!empty($search) && stripos($search, 'id:') === 0) + { + $query->where('extension_id = ' . (int) substr($search, 3)); + } + + return $query; + } +} diff --git a/administrator/components/com_installer/models/update.php b/administrator/components/com_installer/models/update.php new file mode 100644 index 0000000..a9eeca0 --- /dev/null +++ b/administrator/components/com_installer/models/update.php @@ -0,0 +1,383 @@ +getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $value); + + $clientId = $this->getUserStateFromRequest($this->context . '.filter.client_id', 'filter_client_id', ''); + $this->setState('filter.client_id', $clientId); + + $categoryId = $this->getUserStateFromRequest($this->context . '.filter.type', 'filter_type', ''); + $this->setState('filter.type', $categoryId); + + $group = $this->getUserStateFromRequest($this->context . '.filter.group', 'filter_group', ''); + $this->setState('filter.group', $group); + + $this->setState('message', $app->getUserState('com_installer.message')); + $this->setState('extension_message', $app->getUserState('com_installer.extension_message')); + $app->setUserState('com_installer.message', ''); + $app->setUserState('com_installer.extension_message', ''); + + parent::populateState('name', 'asc'); + } + + /** + * Method to get the database query + * + * @return JDatabaseQuery The database query + * + * @since 1.6 + */ + protected function getListQuery() + { + $db = $this->getDbo(); + $query = $db->getQuery(true); + $type = $this->getState('filter.type'); + $client = $this->getState('filter.client_id'); + $group = $this->getState('filter.group'); + + // Grab updates ignoring new installs + $query->select('*') + ->from('#__updates') + ->where('extension_id != 0') + ->order($this->getState('list.ordering') . ' ' . $this->getState('list.direction')); + + if ($type) + { + $query->where('type=' . $db->quote($type)); + } + if ($client != '') + { + $query->where('client_id = ' . intval($client)); + } + if ($group != '' && in_array($type, array('plugin', 'library', ''))) + { + $query->where('folder=' . $db->quote($group == '*' ? '' : $group)); + } + + // Filter by extension_id + if ($eid = $this->getState('filter.extension_id')) + { + $query->where($db->quoteName('extension_id') . ' = ' . $db->quote((int) $eid)); + } + else + { + $query->where($db->quoteName('extension_id') . ' != ' . $db->quote(0)) + ->where($db->quoteName('extension_id') . ' != ' . $db->quote(700)); + } + + // Filter by search + $search = $this->getState('filter.search'); + if (!empty($search)) + { + $query->where('name LIKE ' . $db->quote('%' . $search . '%')); + } + return $query; + } + + /** + * Finds updates for an extension. + * + * @param int $eid Extension identifier to look for + * @param int $cache_timeout Cache timout + * + * @return boolean Result + * + * @since 1.6 + */ + public function findUpdates($eid = 0, $cache_timeout = 0) + { + // Purge the updates list + $this->purge(); + + $updater = JUpdater::getInstance(); + $updater->findUpdates($eid, $cache_timeout); + return true; + } + + /** + * Removes all of the updates from the table. + * + * @return boolean result of operation + * + * @since 1.6 + */ + public function purge() + { + $db = JFactory::getDbo(); + + // Note: TRUNCATE is a DDL operation + // This may or may not mean depending on your database + $db->setQuery('TRUNCATE TABLE #__updates'); + if ($db->execute()) + { + // Reset the last update check timestamp + $query = $db->getQuery(true) + ->update($db->quoteName('#__update_sites')) + ->set($db->quoteName('last_check_timestamp') . ' = ' . $db->quote(0)); + $db->setQuery($query); + $db->execute(); + $this->_message = JText::_('COM_INSTALLER_PURGED_UPDATES'); + return true; + } + else + { + $this->_message = JText::_('COM_INSTALLER_FAILED_TO_PURGE_UPDATES'); + return false; + } + } + + /** + * Enables any disabled rows in #__update_sites table + * + * @return boolean result of operation + * + * @since 1.6 + */ + public function enableSites() + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->update('#__update_sites') + ->set('enabled = 1') + ->where('enabled = 0'); + $db->setQuery($query); + if ($db->execute()) + { + if ($rows = $db->getAffectedRows()) + { + $this->_message .= JText::plural('COM_INSTALLER_ENABLED_UPDATES', $rows); + } + return true; + } + else + { + $this->_message .= JText::_('COM_INSTALLER_FAILED_TO_ENABLE_UPDATES'); + return false; + } + } + + /** + * Update function. + * + * Sets the "result" state with the result of the operation. + * + * @param array $uids Array[int] List of updates to apply + * + * @return void + * + * @since 1.6 + */ + public function update($uids) + { + $result = true; + foreach ($uids as $uid) + { + $update = new JUpdate; + $instance = JTable::getInstance('update'); + $instance->load($uid); + $update->loadFromXML($instance->detailsurl); + + // Install sets state and enqueues messages + $res = $this->install($update); + + if ($res) + { + $instance->delete($uid); + } + + $result = $res & $result; + } + + // Set the final state + $this->setState('result', $result); + } + + /** + * Handles the actual update installation. + * + * @param JUpdate $update An update definition + * + * @return boolean Result of install + * + * @since 1.6 + */ + private function install($update) + { + $app = JFactory::getApplication(); + if (isset($update->get('downloadurl')->_data)) + { + $url = $update->downloadurl->_data; + } + else + { + JError::raiseWarning('', JText::_('COM_INSTALLER_INVALID_EXTENSION_UPDATE')); + return false; + } + + $p_file = JInstallerHelper::downloadPackage($url); + + // Was the package downloaded? + if (!$p_file) + { + JError::raiseWarning('', JText::sprintf('COM_INSTALLER_PACKAGE_DOWNLOAD_FAILED', $url)); + return false; + } + + $config = JFactory::getConfig(); + $tmp_dest = $config->get('tmp_path'); + + // Unpack the downloaded package file + $package = JInstallerHelper::unpack($tmp_dest . '/' . $p_file); + + // Get an installer instance + $installer = JInstaller::getInstance(); + $update->set('type', $package['type']); + + // Install the package + if (!$installer->update($package['dir'])) + { + // There was an error updating the package + $msg = JText::sprintf('COM_INSTALLER_MSG_UPDATE_ERROR', JText::_('COM_INSTALLER_TYPE_TYPE_' . strtoupper($package['type']))); + $result = false; + } + else + { + // Package updated successfully + $msg = JText::sprintf('COM_INSTALLER_MSG_UPDATE_SUCCESS', JText::_('COM_INSTALLER_TYPE_TYPE_' . strtoupper($package['type']))); + $result = true; + } + + // Quick change + $this->type = $package['type']; + + // Set some model state values + $app->enqueueMessage($msg); + + // TODO: Reconfigure this code when you have more battery life left + $this->setState('name', $installer->get('name')); + $this->setState('result', $result); + $app->setUserState('com_installer.message', $installer->message); + $app->setUserState('com_installer.extension_message', $installer->get('extension_message')); + + // Cleanup the install files + if (!is_file($package['packagefile'])) + { + $config = JFactory::getConfig(); + $package['packagefile'] = $config->get('tmp_path') . '/' . $package['packagefile']; + } + + JInstallerHelper::cleanupInstall($package['packagefile'], $package['extractdir']); + + return $result; + } + + /** + * Method to get the row form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * + * @return mixed A JForm object on success, false on failure + * + * @since 2.5.2 + */ + public function getForm($data = array(), $loadData = true) + { + // Get the form. + JForm::addFormPath(JPATH_COMPONENT . '/models/forms'); + JForm::addFieldPath(JPATH_COMPONENT . '/models/fields'); + $form = JForm::getInstance('com_installer.update', 'update', array('load_data' => $loadData)); + + // Check for an error. + if ($form == false) + { + $this->setError($form->getMessage()); + return false; + } + // Check the session for previously entered form data. + $data = $this->loadFormData(); + + // Bind the form data if present. + if (!empty($data)) + { + $form->bind($data); + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * + * @since 2.5.2 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState($this->context . '.data', array()); + return $data; + } +} diff --git a/administrator/components/com_installer/models/warnings.php b/administrator/components/com_installer/models/warnings.php new file mode 100644 index 0000000..34ffb44 --- /dev/null +++ b/administrator/components/com_installer/models/warnings.php @@ -0,0 +1,144 @@ + JText::_('COM_INSTALLER_MSG_WARNINGS_FILEUPLOADSDISABLED'), + 'description' => JText::_('COM_INSTALLER_MSG_WARNINGS_FILEUPLOADISDISABLEDDESC')); + } + + $upload_dir = ini_get('upload_tmp_dir'); + if (!$upload_dir) + { + $messages[] = array('message' => JText::_('COM_INSTALLER_MSG_WARNINGS_PHPUPLOADNOTSET'), + 'description' => JText::_('COM_INSTALLER_MSG_WARNINGS_PHPUPLOADNOTSETDESC')); + } + else + { + if (!is_writeable($upload_dir)) + { + $messages[] = array('message' => JText::_('COM_INSTALLER_MSG_WARNINGS_PHPUPLOADNOTWRITEABLE'), + 'description' => JText::sprintf('COM_INSTALLER_MSG_WARNINGS_PHPUPLOADNOTWRITEABLEDESC', $upload_dir)); + } + } + + $config = JFactory::getConfig(); + $tmp_path = $config->get('tmp_path'); + if (!$tmp_path) + { + $messages[] = array('message' => JText::_('COM_INSTALLER_MSG_WARNINGS_JOOMLATMPNOTSET'), + 'description' => JText::_('COM_INSTALLER_MSG_WARNINGS_JOOMLATMPNOTSETDESC')); + } + else + { + if (!is_writeable($tmp_path)) + { + $messages[] = array('message' => JText::_('COM_INSTALLER_MSG_WARNINGS_JOOMLATMPNOTWRITEABLE'), + 'description' => JText::sprintf('COM_INSTALLER_MSG_WARNINGS_JOOMLATMPNOTWRITEABLEDESC', $tmp_path)); + } + } + + $memory_limit = $this->return_bytes(ini_get('memory_limit')); + if ($memory_limit < (8 * 1024 * 1024)) + { + // 8MB + $messages[] = array('message' => JText::_('COM_INSTALLER_MSG_WARNINGS_LOWMEMORYWARN'), + 'description' => JText::_('COM_INSTALLER_MSG_WARNINGS_LOWMEMORYDESC')); + } + elseif ($memory_limit < (16 * 1024 * 1024)) + { + // 16MB + $messages[] = array('message' => JText::_('COM_INSTALLER_MSG_WARNINGS_MEDMEMORYWARN'), + 'description' => JText::_('COM_INSTALLER_MSG_WARNINGS_MEDMEMORYDESC')); + } + + $post_max_size = $this->return_bytes(ini_get('post_max_size')); + $upload_max_filesize = $this->return_bytes(ini_get('upload_max_filesize')); + + if ($post_max_size < $upload_max_filesize) + { + $messages[] = array('message' => JText::_('COM_INSTALLER_MSG_WARNINGS_UPLOADBIGGERTHANPOST'), + 'description' => JText::_('COM_INSTALLER_MSG_WARNINGS_UPLOADBIGGERTHANPOSTDESC')); + } + + if ($post_max_size < (4 * 1024 * 1024)) // 4MB + { + $messages[] = array('message' => JText::_('COM_INSTALLER_MSG_WARNINGS_SMALLPOSTSIZE'), + 'description' => JText::_('COM_INSTALLER_MSG_WARNINGS_SMALLPOSTSIZEDESC')); + } + + if ($upload_max_filesize < (4 * 1024 * 1024)) // 4MB + { + $messages[] = array('message' => JText::_('COM_INSTALLER_MSG_WARNINGS_SMALLUPLOADSIZE'), + 'description' => JText::_('COM_INSTALLER_MSG_WARNINGS_SMALLUPLOADSIZEDESC')); + } + + return $messages; + } +} diff --git a/administrator/components/com_installer/views/database/index.html b/administrator/components/com_installer/views/database/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/database/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/database/tmpl/default.php b/administrator/components/com_installer/views/database/tmpl/default.php new file mode 100644 index 0000000..de74b42 --- /dev/null +++ b/administrator/components/com_installer/views/database/tmpl/default.php @@ -0,0 +1,86 @@ + + +
+
+ + sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ + errorCount === 0) : ?> +
+ × + +
+ 'other')); ?> + +
+ × + +
+ 'problems')); ?> + errorCount)); ?> +
+
    + filterParams) : ?> +
  • + + + schemaVersion, JVERSION, 5) === 0)) : ?> +
  • schemaVersion, JVERSION); ?>
  • + + + updateVersion != JVERSION)) : ?> +
  • updateVersion, JVERSION); ?>
  • + + + errors as $line => $error) : ?> + queryType; + $msgs = $error->msgElements; + $file = basename($error->file); + $msg0 = (isset($msgs[0])) ? $msgs[0] : ' '; + $msg1 = (isset($msgs[1])) ? $msgs[1] : ' '; + $msg2 = (isset($msgs[2])) ? $msgs[2] : ' '; + $message = JText::sprintf($key, $file, $msg0, $msg1, $msg2); ?> +
  • + +
+
+ + + + +
+
+
    +
  • schemaVersion); ?>
  • +
  • updateVersion); ?>
  • +
  • name); ?>
  • +
  • results['ok'])); ?>
  • +
  • results['skipped'])); ?>
  • +
+
+
+ + + + + +
+ +
diff --git a/administrator/components/com_installer/views/database/tmpl/index.html b/administrator/components/com_installer/views/database/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/database/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/database/view.html.php b/administrator/components/com_installer/views/database/view.html.php new file mode 100644 index 0000000..388f42f --- /dev/null +++ b/administrator/components/com_installer/views/database/view.html.php @@ -0,0 +1,80 @@ +state = $this->get('State'); + $this->changeSet = $this->get('Items'); + $this->errors = $this->changeSet->check(); + $this->results = $this->changeSet->getStatus(); + $this->schemaVersion = $this->get('SchemaVersion'); + $this->updateVersion = $this->get('UpdateVersion'); + $this->filterParams = $this->get('DefaultTextFilters'); + $this->schemaVersion = ($this->schemaVersion) ? $this->schemaVersion : JText::_('JNONE'); + $this->updateVersion = ($this->updateVersion) ? $this->updateVersion : JText::_('JNONE'); + $this->pagination = $this->get('Pagination'); + $this->errorCount = count($this->errors); + + if (!(strncmp($this->schemaVersion, JVERSION, 5) === 0)) + { + $this->errorCount++; + } + if (!$this->filterParams) + { + $this->errorCount++; + } + if (($this->updateVersion != JVERSION)) + { + $this->errorCount++; + } + + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.6 + */ + protected function addToolbar() + { + /* + * Set toolbar items for the page + */ + JToolbarHelper::custom('database.fix', 'refresh', 'refresh', 'COM_INSTALLER_TOOLBAR_DATABASE_FIX', false, false); + JToolbarHelper::divider(); + parent::addToolbar(); + JToolbarHelper::help('JHELP_EXTENSIONS_EXTENSION_MANAGER_DATABASE'); + } +} diff --git a/administrator/components/com_installer/views/default/index.html b/administrator/components/com_installer/views/default/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/default/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/default/tmpl/default_ftp.php b/administrator/components/com_installer/views/default/tmpl/default_ftp.php new file mode 100644 index 0000000..3fec65f --- /dev/null +++ b/administrator/components/com_installer/views/default/tmpl/default_ftp.php @@ -0,0 +1,42 @@ + +
+ + + + + ftp instanceof Exception) : ?> +

ftp->getMessage()); ?>

+ + + + + + + + + + + + + +
+ + + +
+ + + +
+ +
diff --git a/administrator/components/com_installer/views/default/tmpl/default_message.php b/administrator/components/com_installer/views/default/tmpl/default_message.php new file mode 100644 index 0000000..5100178 --- /dev/null +++ b/administrator/components/com_installer/views/default/tmpl/default_message.php @@ -0,0 +1,29 @@ +get('State'); +$message1 = $state->get('message'); +$message2 = $state->get('extension_message'); +?> + + + + + + + + + + + + + +
diff --git a/administrator/components/com_installer/views/default/tmpl/index.html b/administrator/components/com_installer/views/default/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/default/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/default/view.php b/administrator/components/com_installer/views/default/view.php new file mode 100644 index 0000000..ea59919 --- /dev/null +++ b/administrator/components/com_installer/views/default/view.php @@ -0,0 +1,91 @@ +_addPath('template', $this->_basePath . '/views/default/tmpl'); + $this->_addPath('template', JPATH_THEMES . '/' . $app->getTemplate() . '/html/com_installer/default'); + } + + /** + * Display the view + * + * @param string $tpl Template + * + * @return void + * + * @since 1.5 + */ + public function display($tpl = null) + { + // Get data from the model + $state = $this->get('State'); + + // Are there messages to display ? + $showMessage = false; + if (is_object($state)) + { + $message1 = $state->get('message'); + $message2 = $state->get('extension_message'); + $showMessage = ($message1 || $message2); + } + + $this->showMessage = $showMessage; + $this->state = &$state; + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.6 + */ + protected function addToolbar() + { + $canDo = InstallerHelper::getActions(); + JToolbarHelper::title(JText::_('COM_INSTALLER_HEADER_' . $this->getName()), 'install.png'); + + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_installer'); + JToolbarHelper::divider(); + } + + // Document + $document = JFactory::getDocument(); + $document->setTitle(JText::_('COM_INSTALLER_TITLE_' . $this->getName())); + + // Render side bar + $this->sidebar = JHtmlSidebar::render(); + } +} diff --git a/administrator/components/com_installer/views/discover/index.html b/administrator/components/com_installer/views/discover/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/discover/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/discover/tmpl/default.php b/administrator/components/com_installer/views/discover/tmpl/default.php new file mode 100644 index 0000000..8db694f --- /dev/null +++ b/administrator/components/com_installer/views/discover/tmpl/default.php @@ -0,0 +1,93 @@ +escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +?> +
+
+ + sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ + + showMessage) : ?> + loadTemplate('message'); ?> + + + ftp) : ?> + loadTemplate('ftp'); ?> + + + + items)) : ?> + + + + + + + + + + + + + + + + + + items as $i => $item) : ?> + + + + + + + + + + + + + +
pagination->getListFooter(); ?>
extension_id); ?>name; ?>type); ?>version != '' ? $item->version : ' '; ?>creationDate != '' ? $item->creationDate : ' '; ?>folder != '' ? $item->folder : JText::_('COM_INSTALLER_TYPE_NONAPPLICABLE'); ?>client; ?> + + author != '' ? $item->author : ' '; ?> + + extension_id ?>
+ + +

+ +

+
+ +
+ + + + + + + +
+ +
diff --git a/administrator/components/com_installer/views/discover/tmpl/default_item.php b/administrator/components/com_installer/views/discover/tmpl/default_item.php new file mode 100644 index 0000000..c1485ce --- /dev/null +++ b/administrator/components/com_installer/views/discover/tmpl/default_item.php @@ -0,0 +1,35 @@ + +item->index % 2; ?>" item->style; ?>> + + item->cbd; ?> /> + + item->name; ?> + + + item->type ?> + + + item->element) : ?> + X + + item->img, $this->item->alt, array('title' => $this->item->action)); ?> + + + item->folder != '' ? $this->item->folder : 'N/A'; ?> + item->client != '' ? $this->item->client : 'N/A'; ?> + + + item->author != '' ? $this->item->author : ' '; ?> + + + diff --git a/administrator/components/com_installer/views/discover/tmpl/index.html b/administrator/components/com_installer/views/discover/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/discover/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/discover/view.html.php b/administrator/components/com_installer/views/discover/view.html.php new file mode 100644 index 0000000..379e536 --- /dev/null +++ b/administrator/components/com_installer/views/discover/view.html.php @@ -0,0 +1,60 @@ +state = $this->get('State'); + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.6 + */ + protected function addToolbar() + { + /* + * Set toolbar items for the page + */ + JToolbarHelper::custom('discover.install', 'upload', 'upload', 'JTOOLBAR_INSTALL', true, false); + JToolbarHelper::custom('discover.refresh', 'refresh', 'refresh', 'COM_INSTALLER_TOOLBAR_DISCOVER', false, false); + JToolbarHelper::divider(); + parent::addToolbar(); + JToolbarHelper::help('JHELP_EXTENSIONS_EXTENSION_MANAGER_DISCOVER'); + } +} diff --git a/administrator/components/com_installer/views/index.html b/administrator/components/com_installer/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/install/index.html b/administrator/components/com_installer/views/install/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/install/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/install/tmpl/default.php b/administrator/components/com_installer/views/install/tmpl/default.php new file mode 100644 index 0000000..94202e1 --- /dev/null +++ b/administrator/components/com_installer/views/install/tmpl/default.php @@ -0,0 +1,135 @@ + + + +
+
+ sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ + + + showMessage) : ?> + loadTemplate('message'); ?> + + + 'upload')); ?> + + +
+ +
+ +
+ +
+
+
+ +
+
+ + + +
+ +
+ +
+ +
+
+
+ +
+
+ + + +
+ +
+ +
+ +
+
+
+ +
+
+ + + ftp) : ?> + + loadTemplate('ftp'); ?> + + + + + + + + + + +
diff --git a/administrator/components/com_installer/views/install/tmpl/index.html b/administrator/components/com_installer/views/install/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/install/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/install/view.html.php b/administrator/components/com_installer/views/install/view.html.php new file mode 100644 index 0000000..8735383 --- /dev/null +++ b/administrator/components/com_installer/views/install/view.html.php @@ -0,0 +1,56 @@ +first = ''; + $state = $this->get('state'); + + $this->paths = &$paths; + $this->state = &$state; + + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.6 + */ + protected function addToolbar() + { + parent::addToolbar(); + JToolbarHelper::help('JHELP_EXTENSIONS_EXTENSION_MANAGER_INSTALL'); + } +} diff --git a/administrator/components/com_installer/views/languages/index.html b/administrator/components/com_installer/views/languages/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/languages/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/languages/tmpl/default.php b/administrator/components/com_installer/views/languages/tmpl/default.php new file mode 100644 index 0000000..599b8c0 --- /dev/null +++ b/administrator/components/com_installer/views/languages/tmpl/default.php @@ -0,0 +1,109 @@ +escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); + +$version = new JVersion; + +?> + +
+
+ sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ + + items) || $this->escape($this->state->get('filter.search'))) : ?> + loadTemplate('filter'); ?> + + + + + + + + + + + + + + + + + + items as $i => $language) : + ?> + + + + + + + + + + +
+ + + + + + + + + + + +
+ pagination->getListFooter(); ?> +
+ update_id, false, 'cid'); ?> + + name; ?> + + + version, 0, 3) != $version->RELEASE + || substr($language->version, 0, 5) != $version->RELEASE . "." . $version->DEV_LEVEL) : ?> +
+ +
+ version; ?> + + type)); ?> + + detailsurl; ?> + + update_id; ?> +
+ +
+ + + + + + + +
+ +
diff --git a/administrator/components/com_installer/views/languages/tmpl/default_filter.php b/administrator/components/com_installer/views/languages/tmpl/default_filter.php new file mode 100644 index 0000000..eb6616c --- /dev/null +++ b/administrator/components/com_installer/views/languages/tmpl/default_filter.php @@ -0,0 +1,27 @@ + +
+
+ + pagination->getLimitBox(); ?> +
+ +
+ + +
+
+
diff --git a/administrator/components/com_installer/views/languages/tmpl/index.html b/administrator/components/com_installer/views/languages/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/languages/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/languages/view.html.php b/administrator/components/com_installer/views/languages/view.html.php new file mode 100644 index 0000000..188501f --- /dev/null +++ b/administrator/components/com_installer/views/languages/view.html.php @@ -0,0 +1,82 @@ +state = $this->get('State'); + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + */ + protected function addToolbar() + { + $canDo = InstallerHelper::getActions(); + JToolBarHelper::title(JText::_('COM_INSTALLER_HEADER_' . $this->getName()), 'install.png'); + + if ($canDo->get('core.admin')) + { + JToolBarHelper::custom('languages.install', 'upload', 'upload', 'COM_INSTALLER_TOOLBAR_INSTALL', true, false); + JToolBarHelper::custom('languages.find', 'refresh', 'refresh', 'COM_INSTALLER_TOOLBAR_FIND_LANGUAGES', false, false); + JToolBarHelper::divider(); + parent::addToolbar(); + + // TODO: this help screen will need to be created + JToolBarHelper::help('JHELP_EXTENSIONS_EXTENSION_MANAGER_LANGUAGES'); + } + } +} diff --git a/administrator/components/com_installer/views/manage/index.html b/administrator/components/com_installer/views/manage/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/manage/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/manage/tmpl/default.php b/administrator/components/com_installer/views/manage/tmpl/default.php new file mode 100644 index 0000000..9f4004c --- /dev/null +++ b/administrator/components/com_installer/views/manage/tmpl/default.php @@ -0,0 +1,150 @@ +escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +?> +
+
+ sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ + + showMessage) : ?> + loadTemplate('message'); ?> + + + ftp) : ?> + loadTemplate('ftp'); ?> + +
+
+ + pagination->getLimitBox(); ?> +
+ +
+ + +
+
+
+ + items)) : ?> + + + + + + + + + + + + + + + + + + + + + + items as $i => $item) : ?> + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ pagination->getListFooter(); ?> +
+ extension_id); ?> + + + name; ?> + + + client; ?> + + element) : ?> + X + + status, $i, $item->status < 2, 'cb'); ?> + + + type); ?> + + version != '' ? $item->version : ' '; ?> + + creationDate != '' ? $item->creationDate : ' '; ?> + + + author != '' ? $item->author : ' '; ?> + + + folder != '' ? $item->folder : JText::_('COM_INSTALLER_TYPE_NONAPPLICABLE'); ?> + + extension_id ?> +
+ + + + + + + + +
+ +
diff --git a/administrator/components/com_installer/views/manage/tmpl/index.html b/administrator/components/com_installer/views/manage/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/manage/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/manage/view.html.php b/administrator/components/com_installer/views/manage/view.html.php new file mode 100644 index 0000000..3737826 --- /dev/null +++ b/administrator/components/com_installer/views/manage/view.html.php @@ -0,0 +1,124 @@ +state = $this->get('State'); + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + // Check if there are no matching items + if (!count($this->items)) + { + JFactory::getApplication()->enqueueMessage( + JText::_('COM_INSTALLER_MSG_MANAGE_NOEXTENSION'), + 'warning' + ); + } + + // Include the component HTML helpers. + JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html'); + + // Display the view + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.6 + */ + protected function addToolbar() + { + $canDo = InstallerHelper::getActions(); + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::publish('manage.publish', 'JTOOLBAR_ENABLE', true); + JToolbarHelper::unpublish('manage.unpublish', 'JTOOLBAR_DISABLE', true); + JToolbarHelper::divider(); + } + JToolbarHelper::custom('manage.refresh', 'refresh', 'refresh', 'JTOOLBAR_REFRESH_CACHE', true); + JToolbarHelper::divider(); + if ($canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'manage.remove', 'JTOOLBAR_UNINSTALL'); + JToolbarHelper::divider(); + } + + JToolbarHelper::help('JHELP_EXTENSIONS_EXTENSION_MANAGER_MANAGE'); + + JHtmlSidebar::setAction('index.php?option=com_installer&view=manage'); + + JHtmlSidebar::addFilter( + JText::_('COM_INSTALLER_VALUE_CLIENT_SELECT'), + 'filter_client_id', + JHtml::_('select.options', array('0' => 'JSITE', '1' => 'JADMINISTRATOR'), 'value', 'text', $this->state->get('filter.client_id'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('COM_INSTALLER_VALUE_STATE_SELECT'), + 'filter_status', + JHtml::_('select.options', array('0' => 'JDISABLED', '1' => 'JENABLED', '2' => 'JPROTECTED', '3' => 'JUNPROTECTED'), 'value', 'text', $this->state->get('filter.status'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('COM_INSTALLER_VALUE_TYPE_SELECT'), + 'filter_type', + JHtml::_('select.options', InstallerHelper::getExtensionTypes(), 'value', 'text', $this->state->get('filter.type'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('COM_INSTALLER_VALUE_FOLDER_SELECT'), + 'filter_group', + JHtml::_('select.options', array_merge(InstallerHelper::getExtensionGroupes(), array('*' => JText::_('COM_INSTALLER_VALUE_FOLDER_NONAPPLICABLE'))), 'value', 'text', $this->state->get('filter.group'), true) + ); + + parent::addToolbar(); + } +} diff --git a/administrator/components/com_installer/views/update/index.html b/administrator/components/com_installer/views/update/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/update/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/update/tmpl/default.php b/administrator/components/com_installer/views/update/tmpl/default.php new file mode 100644 index 0000000..8a4027f --- /dev/null +++ b/administrator/components/com_installer/views/update/tmpl/default.php @@ -0,0 +1,148 @@ +escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +?> +
+
+ sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ + + showMessage) : ?> +
+ × + loadTemplate('message'); ?> +
+ + + ftp) : ?> + loadTemplate('ftp'); ?> + +
+
+ + pagination->getLimitBox(); ?> +
+ +
+ + +
+
+
+ + + items)) : ?> + + + + + + + + + + + + + + + + + + + + items as $i => $item) : + $client = $item->client_id ? JText::_('JADMINISTRATOR') : JText::_('JSITE'); + ?> + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ pagination->getListFooter(); ?> +
+ update_id); ?> + + + escape($item->name); ?> + + + extension_id ? JText::_('COM_INSTALLER_MSG_UPDATE_UPDATE') : JText::_('COM_INSTALLER_NEW_INSTALL') ?> + + type) ?> + + version ?> + + folder != '' ? $item->folder : JText::_('COM_INSTALLER_TYPE_NONAPPLICABLE'); ?> + + + detailsurl ?> + infourl)) : ?> +
+ + escape($item->infourl); ?> + + +
+ +
+ × + +
+ + + + + + + +
+ +
diff --git a/administrator/components/com_installer/views/update/tmpl/index.html b/administrator/components/com_installer/views/update/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/update/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/update/view.html.php b/administrator/components/com_installer/views/update/view.html.php new file mode 100644 index 0000000..79b0f0d --- /dev/null +++ b/administrator/components/com_installer/views/update/view.html.php @@ -0,0 +1,114 @@ +state = $this->get('State'); + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $paths = new stdClass; + $paths->first = ''; + + $this->paths = &$paths; + if (count($this->items) > 0) + { + $app->enqueueMessage(JText::_('COM_INSTALLER_MSG_WARNINGS_UPDATE_NOTICE'), 'notice'); + } + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.6 + */ + protected function addToolbar() + { + JToolbarHelper::custom('update.update', 'upload', 'upload', 'COM_INSTALLER_TOOLBAR_UPDATE', true, false); + JToolbarHelper::custom('update.find', 'refresh', 'refresh', 'COM_INSTALLER_TOOLBAR_FIND_UPDATES', false, false); + JToolbarHelper::divider(); + + JToolbarHelper::help('JHELP_EXTENSIONS_EXTENSION_MANAGER_UPDATE'); + JHtmlSidebar::setAction('index.php?option=com_installer&view=manage'); + + JHtmlSidebar::addFilter( + JText::_('COM_INSTALLER_VALUE_CLIENT_SELECT'), + 'filter_client_id', + JHtml::_('select.options', array('0' => 'JSITE', '1' => 'JADMINISTRATOR'), 'value', 'text', $this->state->get('filter.client_id'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('COM_INSTALLER_VALUE_TYPE_SELECT'), + 'filter_type', + JHtml::_('select.options', InstallerHelper::getExtensionTypes(), 'value', 'text', $this->state->get('filter.type'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('COM_INSTALLER_VALUE_FOLDER_SELECT'), + 'filter_group', + JHtml::_( + 'select.options', + array_merge(InstallerHelper::getExtensionGroupes(), array('*' => JText::_('COM_INSTALLER_VALUE_FOLDER_NONAPPLICABLE'))), + 'value', + 'text', + $this->state->get('filter.group'), + true + ) + ); + parent::addToolbar(); + } +} diff --git a/administrator/components/com_installer/views/warnings/index.html b/administrator/components/com_installer/views/warnings/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/warnings/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/warnings/tmpl/default.php b/administrator/components/com_installer/views/warnings/tmpl/default.php new file mode 100644 index 0000000..2d041e8 --- /dev/null +++ b/administrator/components/com_installer/views/warnings/tmpl/default.php @@ -0,0 +1,49 @@ + +
+
+ sidebar)) : ?> +
+ sidebar; ?> +
+
+ +
+ + messages)) + { + echo '
×'. JText::_('COM_INSTALLER_MSG_WARNINGS_NONE').'
'; + } + else + { + echo JHtml::_('sliders.start', 'warning-sliders', array('useCookie' => 1)); + + foreach($this->messages as $message) + { + echo JHtml::_('sliders.panel', $message['message'], str_replace(' ', '', $message['message'])); + echo '
'.$message['description'].'
'; + } + echo JHtml::_('sliders.panel', JText::_('COM_INSTALLER_MSG_WARNINGFURTHERINFO'), 'furtherinfo-pane'); + echo '
'. JText::_('COM_INSTALLER_MSG_WARNINGFURTHERINFODESC') .'
'; + echo JHtml::_('sliders.end'); + } + ?> +
+
+ + +
+
+ +
diff --git a/administrator/components/com_installer/views/warnings/tmpl/index.html b/administrator/components/com_installer/views/warnings/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_installer/views/warnings/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_installer/views/warnings/view.html.php b/administrator/components/com_installer/views/warnings/view.html.php new file mode 100644 index 0000000..461656c --- /dev/null +++ b/administrator/components/com_installer/views/warnings/view.html.php @@ -0,0 +1,51 @@ +get('Items'); + $this->messages = &$items; + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.6 + */ + protected function addToolbar() + { + parent::addToolbar(); + JToolbarHelper::help('JHELP_EXTENSIONS_EXTENSION_MANAGER_WARNINGS'); + } +} diff --git a/administrator/components/com_joomlaupdate/access.xml b/administrator/components/com_joomlaupdate/access.xml new file mode 100644 index 0000000..caa29f7 --- /dev/null +++ b/administrator/components/com_joomlaupdate/access.xml @@ -0,0 +1,9 @@ + + +
+ + + + +
+
diff --git a/administrator/components/com_joomlaupdate/config.xml b/administrator/components/com_joomlaupdate/config.xml new file mode 100644 index 0000000..eaa1899 --- /dev/null +++ b/administrator/components/com_joomlaupdate/config.xml @@ -0,0 +1,48 @@ + + +
+ + + + + + + + + + +
+ +
+ + +
+
diff --git a/administrator/components/com_joomlaupdate/controller.php b/administrator/components/com_joomlaupdate/controller.php new file mode 100644 index 0000000..c6d78ad --- /dev/null +++ b/administrator/components/com_joomlaupdate/controller.php @@ -0,0 +1,64 @@ +input->get('view', 'default'); + $vFormat = $document->getType(); + $lName = $this->input->get('layout', 'default'); + + // Get and render the view. + if ($view = $this->getView($vName, $vFormat)) + { + $ftp = JClientHelper::setCredentialsFromRequest('ftp'); + $view->ftp = &$ftp; + + // Get the model for the view. + $model = $this->getModel($vName); + + // Perform update source preference check and refresh update information + $model->applyUpdateSite(); + $model->refreshUpdates(); + + // Push the model into the view (as default). + $view->setModel($model, true); + $view->setLayout($lName); + + // Push document object into the view. + $view->document = $document; + $view->display(); + } + + return $this; + } +} diff --git a/administrator/components/com_joomlaupdate/controllers/index.html b/administrator/components/com_joomlaupdate/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_joomlaupdate/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_joomlaupdate/controllers/update.php b/administrator/components/com_joomlaupdate/controllers/update.php new file mode 100644 index 0000000..2321262 --- /dev/null +++ b/administrator/components/com_joomlaupdate/controllers/update.php @@ -0,0 +1,191 @@ +_applyCredentials(); + + $model = $this->getModel('Default'); + $file = $model->download(); + + $message = null; + $messageType = null; + + if ($file) + { + JFactory::getApplication()->setUserState('com_joomlaupdate.file', $file); + $url = 'index.php?option=com_joomlaupdate&task=update.install'; + } + else + { + JFactory::getApplication()->setUserState('com_joomlaupdate.file', null); + $url = 'index.php?option=com_joomlaupdate'; + $message = JText::_('COM_JOOMLAUPDATE_VIEW_UPDATE_DOWNLOADFAILED'); + } + + $this->setRedirect($url, $message, $messageType); + } + + /** + * Start the installation of the new Joomla! version + * + * @return void + * + * @since 2.5.4 + */ + public function install() + { + $this->_applyCredentials(); + + $model = $this->getModel('Default'); + + $file = JFactory::getApplication()->getUserState('com_joomlaupdate.file', null); + $model->createRestorationFile($file); + + $this->display(); + } + + /** + * Finalise the upgrade by running the necessary scripts + * + * @return void + * + * @since 2.5.4 + */ + public function finalise() + { + $this->_applyCredentials(); + + $model = $this->getModel('Default'); + + $model->finaliseUpgrade(); + + $url = 'index.php?option=com_joomlaupdate&task=update.cleanup'; + $this->setRedirect($url); + } + + /** + * Clean up after ourselves + * + * @return void + * + * @since 2.5.4 + */ + public function cleanup() + { + $this->_applyCredentials(); + + $model = $this->getModel('Default'); + + $model->cleanUp(); + + $url = 'index.php?option=com_joomlaupdate&layout=complete'; + $this->setRedirect($url); + } + + /** + * Purges updates. + * + * @return void + * + * @since 3.0 + */ + public function purge() + { + // Purge updates + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + $model = $this->getModel('Default'); + $model->purge(); + + $url = 'index.php?option=com_joomlaupdate'; + $this->setRedirect($url, $model->_message); + } + + /** + * Method to display a view. + * + * @param boolean $cachable If true, the view output will be cached + * @param array $urlparams An array of safe url parameters and their variable types, for valid values see {@link JFilterInput::clean()}. + * + * @return JoomlaupdateControllerUpdate This object to support chaining. + * + * @since 2.5.4 + */ + public function display($cachable = false, $urlparams = array()) + { + // Get the document object. + $document = JFactory::getDocument(); + + // Set the default view name and format from the Request. + $vName = $this->input->get('view', 'update'); + $vFormat = $document->getType(); + $lName = $this->input->get('layout', 'default'); + + // Get and render the view. + if ($view = $this->getView($vName, $vFormat)) + { + // Get the model for the view. + $model = $this->getModel('Default'); + + // Push the model into the view (as default). + $view->setModel($model, true); + $view->setLayout($lName); + + // Push document object into the view. + $view->document = $document; + $view->display(); + } + + return $this; + } + + /** + * Applies FTP credentials to Joomla! itself, when required + * + * @return void + * + * @since 2.5.4 + */ + protected function _applyCredentials() + { + if (!JClientHelper::hasCredentials('ftp')) + { + $user = JFactory::getApplication()->getUserStateFromRequest('com_joomlaupdate.ftp_user', 'ftp_user', null, 'raw'); + $pass = JFactory::getApplication()->getUserStateFromRequest('com_joomlaupdate.ftp_pass', 'ftp_pass', null, 'raw'); + + if ($user != '' && $pass != '') + { + // Add credentials to the session + if (!JClientHelper::setCredentials('ftp', $user, $pass)) + { + JError::raiseWarning('SOME_ERROR_CODE', JText::_('JLIB_CLIENT_ERROR_HELPER_SETCREDENTIALSFROMREQUEST_FAILED')); + } + } + } + } +} diff --git a/administrator/components/com_joomlaupdate/helpers/download.php b/administrator/components/com_joomlaupdate/helpers/download.php new file mode 100644 index 0000000..648a835 --- /dev/null +++ b/administrator/components/com_joomlaupdate/helpers/download.php @@ -0,0 +1,430 @@ + 'Joomla/' . JVERSION); + $context = stream_context_create(array( 'http' => $httpopts )); + $ih = @fopen($url, 'r', false, $context); + } + else + { + + // PHP 4 way (actually, it's just a fallback) + if ( function_exists('ini_set') ) + { + ini_set('user_agent', 'Joomla/' . JVERSION); + } + $ih = @fopen($url, 'r'); + } + + // If fopen() fails, abort + if ( !is_resource($ih) ) + { + return $result; + } + + // Try to download + $bytes = 0; + $result = true; + $return = ''; + while (!feof($ih) && $result) + { + $contents = fread($ih, 4096); + if ($contents === false) + { + @fclose($ih); + $result = false; + return $result; + } + else + { + $bytes += strlen($contents); + if (is_resource($fp)) + { + $result = @fwrite($fp, $contents); + } + else + { + $return .= $contents; + unset($contents); + } + } + } + + @fclose($ih); + + if (is_resource($fp)) + { + return $result; + } + elseif ( $result === true ) + { + return $return; + } + else + { + return $result; + } + } + + /** + * Detect and return available download "adapters" (not really adapters, as + * we don't follow the Adapter pattern, yet) + * + * @return array + * + * @since 2.5.4 + */ + private static function getAdapters() + { + // Detect available adapters + $adapters = array(); + if (self::hasCURL()) + { + $adapters[] = 'curl'; + } + if (self::hasFOPEN()) + { + $adapters[] = 'fopen'; + } + return $adapters; + } + + /** + * Change the permissions of a file, optionally using FTP + * + * @param string $path Absolute path to file + * @param int $mode Permissions, e.g. 0755 + * + * @return boolean True on success + * + * @since 2.5.4 + */ + private static function chmod($path, $mode) + { + if (is_string($mode)) + { + $mode = octdec($mode); + if ( ($mode < 0600) || ($mode > 0777) ) + { + $mode = 0755; + } + } + + $ftpOptions = JClientHelper::getCredentials('ftp'); + + // Check to make sure the path valid and clean + $path = JPath::clean($path); + + if ($ftpOptions['enabled'] == 1) + { + + // Connect the FTP client + $ftp = JClientFtp::getInstance( + $ftpOptions['host'], $ftpOptions['port'], null, + $ftpOptions['user'], $ftpOptions['pass'] + ); + } + + if (@chmod($path, $mode)) + { + $ret = true; + } + elseif ($ftpOptions['enabled'] == 1) + { + // Translate path and delete + $path = JPath::clean(str_replace(JPATH_ROOT, $ftpOptions['root'], $path), '/'); + + // FTP connector throws an error + $ret = $ftp->chmod($path, $mode); + } else + { + return false; + } + return $ret; + } + +} diff --git a/administrator/components/com_joomlaupdate/helpers/index.html b/administrator/components/com_joomlaupdate/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_joomlaupdate/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_joomlaupdate/helpers/joomlaupdate.php b/administrator/components/com_joomlaupdate/helpers/joomlaupdate.php new file mode 100644 index 0000000..c572e66 --- /dev/null +++ b/administrator/components/com_joomlaupdate/helpers/joomlaupdate.php @@ -0,0 +1,44 @@ +set($action->name, $user->authorise($action->name, $assetName)); + } + + return $result; + } +} diff --git a/administrator/components/com_joomlaupdate/helpers/select.php b/administrator/components/com_joomlaupdate/helpers/select.php new file mode 100644 index 0000000..719b141 --- /dev/null +++ b/administrator/components/com_joomlaupdate/helpers/select.php @@ -0,0 +1,38 @@ + diff --git a/administrator/components/com_joomlaupdate/joomlaupdate.php b/administrator/components/com_joomlaupdate/joomlaupdate.php new file mode 100644 index 0000000..347a90b --- /dev/null +++ b/administrator/components/com_joomlaupdate/joomlaupdate.php @@ -0,0 +1,19 @@ +authorise('core.manage', 'com_joomlaupdate')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$controller = JControllerLegacy::getInstance('Joomlaupdate'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_joomlaupdate/joomlaupdate.xml b/administrator/components/com_joomlaupdate/joomlaupdate.xml new file mode 100644 index 0000000..e42005f --- /dev/null +++ b/administrator/components/com_joomlaupdate/joomlaupdate.xml @@ -0,0 +1,30 @@ + + + com_joomlaupdate + Joomla! Project + February 2012 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_JOOMLAUPDATE_XML_DESCRIPTION + + + config.xml + controller.php + index.html + joomlaupdate.php + restore.php + controllers + helpers + models + views + + + language/en-GB.com_joomlaupdate.ini + language/en-GB.com_joomlaupdate.sys.ini + + + + diff --git a/administrator/components/com_joomlaupdate/models/default.php b/administrator/components/com_joomlaupdate/models/default.php new file mode 100644 index 0000000..3197efe --- /dev/null +++ b/administrator/components/com_joomlaupdate/models/default.php @@ -0,0 +1,753 @@ + + * @since 2.5.4 + */ +class JoomlaupdateModelDefault extends JModelLegacy +{ + /** + * Detects if the Joomla! update site currently in use matches the one + * configured in this component. If they don't match, it changes it. + * + * @return void + * + * @since 2.5.4 + */ + public function applyUpdateSite() + { + // Determine the intended update URL + $params = JComponentHelper::getParams('com_joomlaupdate'); + switch ($params->get('updatesource', 'nochange')) + { + // "Long Term Support (LTS) branch - Recommended" + case 'lts': + $updateURL = 'http://update.joomla.org/core/list.xml'; + break; + + // "Short term support (STS) branch" + case 'sts': + $updateURL = 'http://update.joomla.org/core/sts/list_sts.xml'; + break; + + // "Testing" + case 'testing': + $updateURL = 'http://update.joomla.org/core/test/list_test.xml'; + break; + + // "Custom" + case 'custom': + $updateURL = $params->get('customurl', ''); + break; + + // "Do not change" + case 'nochange': + default: + return; + break; + } + + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->select($db->quoteName('us') . '.*') + ->from($db->quoteName('#__update_sites_extensions') . ' AS ' . $db->quoteName('map')) + ->join( + 'INNER', $db->quoteName('#__update_sites') . ' AS ' . $db->quoteName('us') + . ' ON (' . 'us.update_site_id = map.update_site_id)' + ) + ->where('map.extension_id = ' . $db->quote(700)); + $db->setQuery($query); + $update_site = $db->loadObject(); + + if ($update_site->location != $updateURL) + { + // Modify the database record + $update_site->last_check_timestamp = 0; + $update_site->location = $updateURL; + $db->updateObject('#__update_sites', $update_site, 'update_site_id'); + + // Remove cached updates + $query->clear() + ->delete($db->quoteName('#__updates')) + ->where($db->quoteName('extension_id') . ' = ' . $db->quote('700')); + $db->setQuery($query); + $db->execute(); + } + } + + /** + * Makes sure that the Joomla! update cache is up-to-date + * + * @param boolean $force Force reload, ignoring the cache timeout + * + * @return void + * + * @since 2.5.4 + */ + public function refreshUpdates($force = false) + { + if ($force) + { + $cache_timeout = 0; + } + else + { + $update_params = JComponentHelper::getParams('com_installer'); + $cache_timeout = $update_params->get('cachetimeout', 6, 'int'); + $cache_timeout = 3600 * $cache_timeout; + } + $updater = JUpdater::getInstance(); + $updater->findUpdates(700, $cache_timeout); + } + + /** + * Returns an array with the Joomla! update information + * + * @return array + * + * @since 2.5.4 + */ + public function getUpdateInformation() + { + // Initialise the return array + $ret = array( + 'installed' => JVERSION, + 'latest' => null, + 'object' => null + ); + + // Fetch the update information from the database + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->select('*') + ->from($db->quoteName('#__updates')) + ->where($db->quoteName('extension_id') . ' = ' . $db->quote(700)); + $db->setQuery($query); + $updateObject = $db->loadObject(); + + if (is_null($updateObject)) + { + $ret['latest'] = JVERSION; + return $ret; + } + else + { + $ret['latest'] = $updateObject->version; + } + + // Fetch the full udpate details from the update details URL + jimport('joomla.updater.update'); + $update = new JUpdate; + $update->loadFromXML($updateObject->detailsurl); + + // Pass the update object + if ($ret['latest'] == JVERSION) + { + $ret['object'] = null; + } + else + { + $ret['object'] = $update; + } + + return $ret; + } + + /** + * Returns an array with the configured FTP options + * + * @return array + * + * @since 2.5.4 + */ + public function getFTPOptions() + { + $config = JFactory::getConfig(); + return array( + 'host' => $config->get('ftp_host'), + 'port' => $config->get('ftp_port'), + 'username' => $config->get('ftp_user'), + 'password' => $config->get('ftp_pass'), + 'directory' => $config->get('ftp_root'), + 'enabled' => $config->get('ftp_enable'), + ); + } + + /** + * Removes all of the updates from the table and enable all update streams. + * + * @return boolean Result of operation + * + * @since 3.0 + */ + public function purge() + { + $db = JFactory::getDbo(); + + // Modify the database record + $update_site = new stdClass; + $update_site->last_check_timestamp = 0; + $update_site->enabled = 1; + $update_site->update_site_id = 1; + $db->updateObject('#__update_sites', $update_site, 'update_site_id'); + + $query = $db->getQuery(true) + ->delete($db->quoteName('#__updates')) + ->where($db->quoteName('update_site_id') . ' = ' . $db->quote('1')); + $db->setQuery($query); + + if ($db->execute()) + { + $this->_message = JText::_('JLIB_INSTALLER_PURGED_UPDATES'); + return true; + } + else + { + $this->_message = JText::_('JLIB_INSTALLER_FAILED_TO_PURGE_UPDATES'); + return false; + } + } + + /** + * Downloads the update package to the site + * + * @return bool|string False on failure, basename of the file in any other case + * + * @since 2.5.4 + */ + public function download() + { + $updateInfo = $this->getUpdateInformation(); + $packageURL = $updateInfo['object']->downloadurl->_data; + $basename = basename($packageURL); + + // Find the path to the temp directory and the local package + $config = JFactory::getConfig(); + $tempdir = $config->get('tmp_path'); + $target = $tempdir . '/' . $basename; + + // Do we have a cached file? + $exists = JFile::exists($target); + + if (!$exists) + { + // Not there, let's fetch it + return $this->downloadPackage($packageURL, $target); + } + else + { + // Is it a 0-byte file? If so, re-download please. + $filesize = @filesize($target); + if (empty($filesize)) + { + return $this->downloadPackage($packageURL, $target); + } + + // Yes, it's there, skip downloading + return $basename; + } + } + + /** + * Downloads a package file to a specific directory + * + * @param string $url The URL to download from + * @param string $target The directory to store the file + * + * @return boolean True on success + * + * @since 2.5.4 + */ + protected function downloadPackage($url, $target) + { + JLoader::import('helpers.download', JPATH_COMPONENT_ADMINISTRATOR); + $result = AdmintoolsHelperDownload::download($url, $target); + + if (!$result) + { + return false; + } + else + { + return basename($target); + } + } + + /** + * @since 2.5.4 + */ + public function createRestorationFile($basename = null) + { + // Get a password + $password = JUserHelper::genRandomPassword(32); + $app = JFactory::getApplication(); + $app->setUserState('com_joomlaupdate.password', $password); + + // Do we have to use FTP? + $method = $app->input->get('method', 'direct'); + + // Get the absolute path to site's root + $siteroot = JPATH_SITE; + + // If the package name is not specified, get it from the update info + if (empty($basename)) + { + $updateInfo = $this->getUpdateInformation(); + $packageURL = $updateInfo['object']->downloadurl->_data; + $basename = basename($packageURL); + } + + // Get the package name + $config = JFactory::getConfig(); + $tempdir = $config->get('tmp_path'); + $file = $tempdir . '/' . $basename; + + $filesize = @filesize($file); + $app->setUserState('com_joomlaupdate.password', $password); + $app->setUserState('com_joomlaupdate.filesize', $filesize); + + $data = " '$password', + 'kickstart.tuning.max_exec_time' => '5', + 'kickstart.tuning.run_time_bias' => '75', + 'kickstart.tuning.min_exec_time' => '0', + 'kickstart.procengine' => '$method', + 'kickstart.setup.sourcefile' => '$file', + 'kickstart.setup.destdir' => '$siteroot', + 'kickstart.setup.restoreperms' => '0', + 'kickstart.setup.filetype' => 'zip', + 'kickstart.setup.dryrun' => '0' +ENDDATA; + + if ($method == 'ftp') + { + // Fetch the FTP parameters from the request. Note: The password should be + // allowed as raw mode, otherwise something like !@43H% would be + // sanitised to !@43H% which is just plain wrong. + $ftp_host = $app->input->get('ftp_host', ''); + $ftp_port = $app->input->get('ftp_port', '21'); + $ftp_user = $app->input->get('ftp_user', ''); + $ftp_pass = $app->input->get('ftp_pass', '', 'default', 'none', 2); + $ftp_root = $app->input->get('ftp_root', ''); + + // Is the tempdir really writable? + $writable = @is_writeable($tempdir); + if ($writable) + { + // Let's be REALLY sure + $fp = @fopen($tempdir . '/test.txt', 'w'); + if ($fp === false) + { + $writable = false; + } + else + { + fclose($fp); + unlink($tempdir . '/test.txt'); + } + } + + // If the tempdir is not writable, create a new writable subdirectory + if (!$writable) + { + $FTPOptions = JClientHelper::getCredentials('ftp'); + $ftp = JClientFtp::getInstance($FTPOptions['host'], $FTPOptions['port'], null, $FTPOptions['user'], $FTPOptions['pass']); + $dest = JPath::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $tempdir . '/admintools'), '/'); + if (!@mkdir($tempdir . '/admintools')) + { + $ftp->mkdir($dest); + } + if (!@chmod($tempdir . '/admintools', 511)) + { + $ftp->chmod($dest, 511); + } + + $tempdir .= '/admintools'; + } + + // Just in case the temp-directory was off-root, try using the default tmp directory + $writable = @is_writeable($tempdir); + if (!$writable) + { + $tempdir = JPATH_ROOT . '/tmp'; + + // Does the JPATH_ROOT/tmp directory exist? + if (!is_dir($tempdir)) + { + + JFolder::create($tempdir, 511); + JFile::write($tempdir . '/.htaccess', "order deny, allow\ndeny from all\nallow from none\n"); + } + + // If it exists and it is unwritable, try creating a writable admintools subdirectory + if (!is_writable($tempdir)) + { + $FTPOptions = JClientHelper::getCredentials('ftp'); + $ftp = JClientFtp::getInstance($FTPOptions['host'], $FTPOptions['port'], null, $FTPOptions['user'], $FTPOptions['pass']); + $dest = JPath::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $tempdir . '/admintools'), '/'); + if (!@mkdir($tempdir . '/admintools')) + { + $ftp->mkdir($dest); + } + if (!@chmod($tempdir . '/admintools', 511)) + { + $ftp->chmod($dest, 511); + } + + $tempdir .= '/admintools'; + } + } + + // If we still have no writable directory, we'll try /tmp and the system's temp-directory + $writable = @is_writeable($tempdir); + + if (!$writable) + { + if (@is_dir('/tmp') && @is_writable('/tmp')) + { + $tempdir = '/tmp'; + } + else + { + // Try to find the system temp path + $tmpfile = @tempnam("dummy", ""); + $systemp = @dirname($tmpfile); + @unlink($tmpfile); + + if (!empty($systemp)) + { + if (@is_dir($systemp) && @is_writable($systemp)) + { + $tempdir = $systemp; + } + } + } + } + + $data .= << '0', + 'kickstart.ftp.passive' => '1', + 'kickstart.ftp.host' => '$ftp_host', + 'kickstart.ftp.port' => '$ftp_port', + 'kickstart.ftp.user' => '$ftp_user', + 'kickstart.ftp.pass' => '$ftp_pass', + 'kickstart.ftp.dir' => '$ftp_root', + 'kickstart.ftp.tempdir' => '$tempdir' +ENDDATA; + } + + $data .= ');'; + + // Remove the old file, if it's there... + $configpath = JPATH_COMPONENT_ADMINISTRATOR . '/restoration.php'; + if (JFile::exists($configpath)) + { + JFile::delete($configpath); + } + + // Write new file. First try with JFile. + $result = JFile::write($configpath, $data); + // In case JFile used FTP but direct access could help + if (!$result) + { + if (function_exists('file_put_contents')) + { + $result = @file_put_contents($configpath, $data); + if ($result !== false) + { + $result = true; + } + } + else + { + $fp = @fopen($configpath, 'wt'); + + if ($fp !== false) + { + $result = @fwrite($fp, $data); + if ($result !== false) + { + $result = true; + } + @fclose($fp); + } + } + } + return $result; + } + + /** + * Runs the schema update SQL files, the PHP update script and updates the + * manifest cache and #__extensions entry. Essentially, it is identical to + * JInstallerFile::install() without the file copy. + * + * @return boolean True on success + * + * @since 2.5.4 + */ + public function finaliseUpgrade() + { + $installer = JInstaller::getInstance(); + + $installer->setPath('source', JPATH_ROOT); + $installer->setPath('extension_root', JPATH_ROOT); + + if (!$installer->setupInstall()) + { + $installer->abort(JText::_('JLIB_INSTALLER_ABORT_DETECTMANIFEST')); + + return false; + } + + $installer->extension = JTable::getInstance('extension'); + $installer->extension->load(700); + $installer->setAdapter($installer->extension->type); + + $manifest = $installer->getManifest(); + + $manifestPath = JPath::clean($installer->getPath('manifest')); + $element = preg_replace('/\.xml/', '', basename($manifestPath)); + + // Run the script file + $manifestScript = (string) $manifest->scriptfile; + + if ($manifestScript) + { + $manifestScriptFile = JPATH_ROOT . '/' . $manifestScript; + + if (is_file($manifestScriptFile)) + { + // load the file + include_once $manifestScriptFile; + } + + $classname = 'JoomlaInstallerScript'; + + if (class_exists($classname)) + { + $manifestClass = new $classname($this); + } + } + + ob_start(); + ob_implicit_flush(false); + if ($manifestClass && method_exists($manifestClass, 'preflight')) + { + if ($manifestClass->preflight('update', $this) === false) + { + $installer->abort(JText::_('JLIB_INSTALLER_ABORT_FILE_INSTALL_CUSTOM_INSTALL_FAILURE')); + + return false; + } + } + + $msg = ob_get_contents(); // create msg object; first use here + ob_end_clean(); + + // Get a database connector object + $db = JFactory::getDbo(); + + // Check to see if a file extension by the same name is already installed + // If it is, then update the table because if the files aren't there + // we can assume that it was (badly) uninstalled + // If it isn't, add an entry to extensions + $query = $db->getQuery(true) + ->select($db->quoteName('extension_id')) + ->from($db->quoteName('#__extensions')) + ->where($db->quoteName('type') . ' = ' . $db->quote('file')) + ->where($db->quoteName('element') . ' = ' . $db->quote('joomla')); + $db->setQuery($query); + try + { + $db->execute(); + } + catch (RuntimeException $e) + { + // Install failed, roll back changes + $installer->abort( + JText::sprintf('JLIB_INSTALLER_ABORT_FILE_ROLLBACK', JText::_('JLIB_INSTALLER_UPDATE'), $db->stderr(true)) + ); + return false; + } + $id = $db->loadResult(); + $row = JTable::getInstance('extension'); + + if ($id) + { + // Load the entry and update the manifest_cache + $row->load($id); + // Update name + $row->set('name', 'files_joomla'); + // Update manifest + $row->manifest_cache = $installer->generateManifestCache(); + if (!$row->store()) + { + // Install failed, roll back changes + $installer->abort( + JText::sprintf('JLIB_INSTALLER_ABORT_FILE_ROLLBACK', JText::_('JLIB_INSTALLER_UPDATE'), $db->stderr(true)) + ); + return false; + } + } + else + { + // Add an entry to the extension table with a whole heap of defaults + $row->set('name', 'files_joomla'); + $row->set('type', 'file'); + $row->set('element', 'joomla'); + // There is no folder for files so leave it blank + $row->set('folder', ''); + $row->set('enabled', 1); + $row->set('protected', 0); + $row->set('access', 0); + $row->set('client_id', 0); + $row->set('params', ''); + $row->set('system_data', ''); + $row->set('manifest_cache', $installer->generateManifestCache()); + + if (!$row->store()) + { + // Install failed, roll back changes + $installer->abort(JText::sprintf('JLIB_INSTALLER_ABORT_FILE_INSTALL_ROLLBACK', $db->stderr(true))); + return false; + } + + // Set the insert id + $row->set('extension_id', $db->insertid()); + + // Since we have created a module item, we add it to the installation step stack + // so that if we have to rollback the changes we can undo it. + $installer->pushStep(array('type' => 'extension', 'extension_id' => $row->extension_id)); + } + + /* + * Let's run the queries for the file + */ + if ($manifest->update) + { + $result = $installer->parseSchemaUpdates($manifest->update->schemas, $row->extension_id); + if ($result === false) + { + // Install failed, rollback changes + $installer->abort(JText::sprintf('JLIB_INSTALLER_ABORT_FILE_UPDATE_SQL_ERROR', $db->stderr(true))); + return false; + } + } + + // Start Joomla! 1.6 + ob_start(); + ob_implicit_flush(false); + + if ($manifestClass && method_exists($manifestClass, 'update')) + { + if ($manifestClass->update($installer) === false) + { + // Install failed, rollback changes + $installer->abort(JText::_('JLIB_INSTALLER_ABORT_FILE_INSTALL_CUSTOM_INSTALL_FAILURE')); + + return false; + } + } + + $msg .= ob_get_contents(); // append messages + ob_end_clean(); + + // Lastly, we will copy the manifest file to its appropriate place. + $manifest = array(); + $manifest['src'] = $installer->getPath('manifest'); + $manifest['dest'] = JPATH_MANIFESTS . '/files/' . basename($installer->getPath('manifest')); + if (!$installer->copyFiles(array($manifest), true)) + { + // Install failed, rollback changes + $installer->abort(JText::_('JLIB_INSTALLER_ABORT_FILE_INSTALL_COPY_SETUP')); + return false; + } + + // Clobber any possible pending updates + $update = JTable::getInstance('update'); + $uid = $update->find( + array('element' => $element, 'type' => 'file', 'client_id' => '0', 'folder' => '') + ); + + if ($uid) + { + $update->delete($uid); + } + + // And now we run the postflight + ob_start(); + ob_implicit_flush(false); + + if ($manifestClass && method_exists($manifestClass, 'postflight')) + { + $manifestClass->postflight('update', $this); + } + + $msg .= ob_get_contents(); // append messages + ob_end_clean(); + + if ($msg != '') + { + $installer->set('extension_message', $msg); + } + + return true; + } + + /** + * Removes the extracted package file + * + * @return void + * + * @since 2.5.4 + */ + public function cleanUp() + { + // Remove the update package + $config = JFactory::getConfig(); + $tempdir = $config->get('tmp_path'); + + $file = JFactory::getApplication()->getUserState('com_joomlaupdate.file', null); + $target = $tempdir . '/' . $file; + if (!@unlink($target)) + { + JFile::delete($target); + } + + // Remove the restoration.php file + $target = JPATH_COMPONENT_ADMINISTRATOR . '/restoration.php'; + if (!@unlink($target)) + { + JFile::delete($target); + } + + // Remove joomla.xml from the site's root + $target = JPATH_ROOT . '/joomla.xml'; + if (!@unlink($target)) + { + JFile::delete($target); + } + + // Unset the update filename from the session + JFactory::getApplication()->setUserState('com_joomlaupdate.file', null); + } +} diff --git a/administrator/components/com_joomlaupdate/models/index.html b/administrator/components/com_joomlaupdate/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_joomlaupdate/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_joomlaupdate/restore.php b/administrator/components/com_joomlaupdate/restore.php new file mode 100644 index 0000000..3d47bf6 --- /dev/null +++ b/administrator/components/com_joomlaupdate/restore.php @@ -0,0 +1,5746 @@ +|'), + array('*' => '.*', '?' => '.?')) . '$/i', $string + ); + } +} + +// Unicode-safe binary data length function +if(function_exists('mb_strlen')) { + function akstringlen($string) { return mb_strlen($string,'8bit'); } +} else { + function akstringlen($string) { return strlen($string); } +} + +/** + * Gets a query parameter from GET or POST data + * @param $key + * @param $default + */ +function getQueryParam( $key, $default = null ) +{ + $value = null; + + if(array_key_exists($key, $_REQUEST)) { + $value = $_REQUEST[$key]; + } elseif(array_key_exists($key, $_POST)) { + $value = $_POST[$key]; + } elseif(array_key_exists($key, $_GET)) { + $value = $_GET[$key]; + } else { + return $default; + } + + if(get_magic_quotes_gpc() && !is_null($value)) $value=stripslashes($value); + + return $value; +} + +/** + * Akeeba Backup's JSON compatibility layer + * + * On systems where json_encode and json_decode are not available, Akeeba + * Backup will attempt to use PEAR's Services_JSON library to emulate them. + * A copy of this library is included in this file and will be used if and + * only if it isn't already loaded, e.g. due to PEAR's auto-loading, or a + * 3PD extension loading it for its own purposes. + */ + +/** + * Converts to and from JSON format. + * + * JSON (JavaScript Object Notation) is a lightweight data-interchange + * format. It is easy for humans to read and write. It is easy for machines + * to parse and generate. It is based on a subset of the JavaScript + * Programming Language, Standard ECMA-262 3rd Edition - December 1999. + * This feature can also be found in Python. JSON is a text format that is + * completely language independent but uses conventions that are familiar + * to programmers of the C-family of languages, including C, C++, C#, Java, + * JavaScript, Perl, TCL, and many others. These properties make JSON an + * ideal data-interchange language. + * + * This package provides a simple encoder and decoder for JSON notation. It + * is intended for use with client-side Javascript applications that make + * use of HTTPRequest to perform server communication functions - data can + * be encoded into JSON notation for use in a client-side javascript, or + * decoded from incoming Javascript requests. JSON format is native to + * Javascript, and can be directly eval()'ed with no further parsing + * overhead + * + * All strings should be in ASCII or UTF-8 format! + * + * LICENSE: Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: Redistributions of source code must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * @category + * @package Services_JSON + * @author Michal Migurski + * @author Matt Knapp + * @author Brett Stimmerman + * @copyright 2005 Michal Migurski + * @version CVS: $Id: restore.php 612 2011-05-19 08:26:26Z nikosdion $ + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + +if(!defined('JSON_FORCE_OBJECT')) +{ + define('JSON_FORCE_OBJECT', 1); +} + +if(!defined('SERVICES_JSON_SLICE')) +{ + /** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ + define('SERVICES_JSON_SLICE', 1); + + /** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ + define('SERVICES_JSON_IN_STR', 2); + + /** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ + define('SERVICES_JSON_IN_ARR', 3); + + /** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ + define('SERVICES_JSON_IN_OBJ', 4); + + /** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ + define('SERVICES_JSON_IN_CMT', 5); + + /** + * Behavior switch for Services_JSON::decode() + */ + define('SERVICES_JSON_LOOSE_TYPE', 16); + + /** + * Behavior switch for Services_JSON::decode() + */ + define('SERVICES_JSON_SUPPRESS_ERRORS', 32); +} + +/** + * Converts to and from JSON format. + * + * Brief example of use: + * + * + * // create a new instance of Services_JSON + * $json = new Services_JSON(); + * + * // convert a complexe value to JSON notation, and send it to the browser + * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); + * $output = $json->encode($value); + * + * print($output); + * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] + * + * // accept incoming POST data, assumed to be in JSON notation + * $input = file_get_contents('php://input', 1000000); + * $value = $json->decode($input); + * + */ +if(!class_exists('Akeeba_Services_JSON')) +{ + class Akeeba_Services_JSON + { + /** + * constructs a new JSON instance + * + * @param int $use object behavior flags; combine with boolean-OR + * + * possible values: + * - SERVICES_JSON_LOOSE_TYPE: loose typing. + * "{...}" syntax creates associative arrays + * instead of objects in decode(). + * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. + * Values which can't be encoded (e.g. resources) + * appear as NULL instead of throwing errors. + * By default, a deeply-nested resource will + * bubble up with an error, so all return values + * from encode() should be checked with isError() + */ + function Akeeba_Services_JSON($use = 0) + { + $this->use = $use; + } + + /** + * convert a string from one UTF-16 char to one UTF-8 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf16 UTF-16 character + * @return string UTF-8 character + * @access private + */ + function utf162utf8($utf16) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + } + + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch(true) { + case ((0x7F & $bytes) == $bytes): + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) + . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) + . chr(0x80 | (($bytes >> 6) & 0x3F)) + . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + function utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + function encode($var) + { + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + $properties = array_map(array($this, 'name_value'), + array_keys($var), + array_values($var)); + + foreach($properties as $property) { + if(Akeeba_Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + } + + // treat it like a regular array + $elements = array_map(array($this, 'encode'), $var); + + foreach($elements as $element) { + if(Akeeba_Services_JSON::isError($element)) { + return $element; + } + } + + return '[' . join(',', $elements) . ']'; + + case 'object': + $vars = get_object_vars($var); + + $properties = array_map(array($this, 'name_value'), + array_keys($vars), + array_values($vars)); + + foreach($properties as $property) { + if(Akeeba_Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + + default: + return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) + ? 'null' + : new Akeeba_Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + function name_value($name, $value) + { + $encoded_value = $this->encode($value); + + if(Akeeba_Services_JSON::isError($encoded_value)) { + return $encoded_value; + } + + return $this->encode(strval($name)) . ':' . $encoded_value; + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to Akeeba_Services_JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) { + case 'true': + return true; + + case 'false': + return false; + + case 'null': + return null; + + default: + $m = array(); + + if (is_numeric($str)) { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) + ? (integer)$str + : (float)$str; + + } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = substr($str, 0, 1); + $chrs = substr($str, 1, -1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = substr($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { + $utf8 .= $chrs{++$c}; + } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) + . chr(hexdec(substr($chrs, ($c + 4), 2))); + $utf8 .= $this->utf162utf8($utf16); + $c += 5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 6); + $c += 5; + break; + + } + + } + + return $utf8; + + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { + // array, or object notation + + if ($str{0} == '[') { + $stk = array(SERVICES_JSON_IN_ARR); + $arr = array(); + } else { + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = array(); + } else { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => SERVICES_JSON_SLICE, + 'where' => 0, + 'delim' => false)); + + $chrs = substr($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') { + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } else { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = substr($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = substr($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + $parts = array(); + + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } + + } + + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { + // found a quote, and we are not inside a string + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); + + } elseif (($chrs{$c} == $top['delim']) && + ($top['what'] == SERVICES_JSON_IN_STR) && + ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) { + // found a quote, we're in a string, and it's not escaped + // we know that it's not escaped becase there is _not_ an + // odd number of backslashes at the end of the string so far + array_pop($stk); + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '[') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); + + } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '{') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); + + } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($substr_chrs_c_2 == '/*') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); + + } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { + // found a comment end, and we're in one now + array_pop($stk); + $c++; + + for ($i = $top['where']; $i <= $c; ++$i) + $chrs = substr_replace($chrs, ' ', $i, 1); + + //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + + } + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + return $obj; + + } + + } + } + } + + function isError($data, $code = null) + { + if (class_exists('pear')) { + return PEAR::isError($data, $code); + } elseif (is_object($data) && (get_class($data) == 'services_json_error' || + is_subclass_of($data, 'services_json_error'))) { + return true; + } + + return false; + } + } + + class Akeeba_Services_JSON_Error + { + function Akeeba_Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + + } + } +} + +if(!function_exists('json_encode')) +{ + function json_encode($value, $options = 0) { + $flags = SERVICES_JSON_LOOSE_TYPE; + if( $options & JSON_FORCE_OBJECT ) $flags = 0; + $encoder = new Akeeba_Services_JSON($flags); + return $encoder->encode($value); + } +} + +if(!function_exists('json_decode')) +{ + function json_decode($value, $assoc = false) + { + $flags = 0; + if($assoc) $flags = SERVICES_JSON_LOOSE_TYPE; + $decoder = new Akeeba_Services_JSON($flags); + return $decoder->decode($value); + } +} + +/** + * The base class of Akeeba Engine objects. Allows for error and warnings logging + * and propagation. Largely based on the Joomla! 1.5 JObject class. + */ +abstract class AKAbstractObject +{ + /** @var array An array of errors */ + private $_errors = array(); + + /** @var array The queue size of the $_errors array. Set to 0 for infinite size. */ + protected $_errors_queue_size = 0; + + /** @var array An array of warnings */ + private $_warnings = array(); + + /** @var array The queue size of the $_warnings array. Set to 0 for infinite size. */ + protected $_warnings_queue_size = 0; + + /** + * Public constructor, makes sure we are instanciated only by the factory class + */ + public function __construct() + { + /* + // Assisted Singleton pattern + if(function_exists('debug_backtrace')) + { + $caller=debug_backtrace(); + if( + ($caller[1]['class'] != 'AKFactory') && + ($caller[2]['class'] != 'AKFactory') && + ($caller[3]['class'] != 'AKFactory') && + ($caller[4]['class'] != 'AKFactory') + ) { + var_dump(debug_backtrace()); + trigger_error("You can't create direct descendants of ".__CLASS__, E_USER_ERROR); + } + } + */ + } + + /** + * Get the most recent error message + * @param integer $i Optional error index + * @return string Error message + */ + public function getError($i = null) + { + return $this->getItemFromArray($this->_errors, $i); + } + + /** + * Return all errors, if any + * @return array Array of error messages + */ + public function getErrors() + { + return $this->_errors; + } + + /** + * Add an error message + * @param string $error Error message + */ + public function setError($error) + { + if($this->_errors_queue_size > 0) + { + if(count($this->_errors) >= $this->_errors_queue_size) + { + array_shift($this->_errors); + } + } + array_push($this->_errors, $error); + } + + /** + * Resets all error messages + */ + public function resetErrors() + { + $this->_errors = array(); + } + + /** + * Get the most recent warning message + * @param integer $i Optional warning index + * @return string Error message + */ + public function getWarning($i = null) + { + return $this->getItemFromArray($this->_warnings, $i); + } + + /** + * Return all warnings, if any + * @return array Array of error messages + */ + public function getWarnings() + { + return $this->_warnings; + } + + /** + * Add an error message + * @param string $error Error message + */ + public function setWarning($warning) + { + if($this->_warnings_queue_size > 0) + { + if(count($this->_warnings) >= $this->_warnings_queue_size) + { + array_shift($this->_warnings); + } + } + + array_push($this->_warnings, $warning); + } + + /** + * Resets all warning messages + */ + public function resetWarnings() + { + $this->_warnings = array(); + } + + /** + * Propagates errors and warnings to a foreign object. The foreign object SHOULD + * implement the setError() and/or setWarning() methods but DOESN'T HAVE TO be of + * AKAbstractObject type. For example, this can even be used to propagate to a + * JObject instance in Joomla!. Propagated items will be removed from ourself. + * @param object $object The object to propagate errors and warnings to. + */ + public function propagateToObject(&$object) + { + // Skip non-objects + if(!is_object($object)) return; + + if( method_exists($object,'setError') ) + { + if(!empty($this->_errors)) + { + foreach($this->_errors as $error) + { + $object->setError($error); + } + $this->_errors = array(); + } + } + + if( method_exists($object,'setWarning') ) + { + if(!empty($this->_warnings)) + { + foreach($this->_warnings as $warning) + { + $object->setWarning($warning); + } + $this->_warnings = array(); + } + } + } + + /** + * Propagates errors and warnings from a foreign object. Each propagated list is + * then cleared on the foreign object, as long as it implements resetErrors() and/or + * resetWarnings() methods. + * @param object $object The object to propagate errors and warnings from + */ + public function propagateFromObject(&$object) + { + if( method_exists($object,'getErrors') ) + { + $errors = $object->getErrors(); + if(!empty($errors)) + { + foreach($errors as $error) + { + $this->setError($error); + } + } + if(method_exists($object,'resetErrors')) + { + $object->resetErrors(); + } + } + + if( method_exists($object,'getWarnings') ) + { + $warnings = $object->getWarnings(); + if(!empty($warnings)) + { + foreach($warnings as $warning) + { + $this->setWarning($warning); + } + } + if(method_exists($object,'resetWarnings')) + { + $object->resetWarnings(); + } + } + } + + /** + * Sets the size of the error queue (acts like a LIFO buffer) + * @param int $newSize The new queue size. Set to 0 for infinite length. + */ + protected function setErrorsQueueSize($newSize = 0) + { + $this->_errors_queue_size = (int)$newSize; + } + + /** + * Sets the size of the warnings queue (acts like a LIFO buffer) + * @param int $newSize The new queue size. Set to 0 for infinite length. + */ + protected function setWarningsQueueSize($newSize = 0) + { + $this->_warnings_queue_size = (int)$newSize; + } + + /** + * Returns the last item of a LIFO string message queue, or a specific item + * if so specified. + * @param array $array An array of strings, holding messages + * @param int $i Optional message index + * @return mixed The message string, or false if the key doesn't exist + */ + private function getItemFromArray($array, $i = null) + { + // Find the item + if ( $i === null) { + // Default, return the last item + $item = end($array); + } + else + if ( ! array_key_exists($i, $array) ) { + // If $i has been specified but does not exist, return false + return false; + } + else + { + $item = $array[$i]; + } + + return $item; + } + +} + +/** + * File post processor engines base class + */ +abstract class AKAbstractPostproc extends AKAbstractObject +{ + /** @var string The current (real) file path we'll have to process */ + protected $filename = null; + + /** @var int The requested permissions */ + protected $perms = 0755; + + /** @var string The temporary file path we gave to the unarchiver engine */ + protected $tempFilename = null; + + /** @var int The UNIX timestamp of the file's desired modification date */ + public $timestamp = 0; + + /** + * Processes the current file, e.g. moves it from temp to final location by FTP + */ + abstract public function process(); + + /** + * The unarchiver tells us the path to the filename it wants to extract and we give it + * a different path instead. + * @param string $filename The path to the real file + * @param int $perms The permissions we need the file to have + * @return string The path to the temporary file + */ + abstract public function processFilename($filename, $perms = 0755); + + /** + * Recursively creates a directory if it doesn't exist + * @param string $dirName The directory to create + * @param int $perms The permissions to give to that directory + */ + abstract public function createDirRecursive( $dirName, $perms ); + + abstract public function chmod( $file, $perms ); + + abstract public function unlink( $file ); + + abstract public function rmdir( $directory ); + + abstract public function rename( $from, $to ); +} + +/** + * The base class of unarchiver classes + */ +abstract class AKAbstractUnarchiver extends AKAbstractPart +{ + /** @var string Archive filename */ + protected $filename = null; + + /** @var array List of the names of all archive parts */ + public $archiveList = array(); + + /** @var int The total size of all archive parts */ + public $totalSize = array(); + + /** @var integer Current archive part number */ + protected $currentPartNumber = -1; + + /** @var integer The offset inside the current part */ + protected $currentPartOffset = 0; + + /** @var bool Should I restore permissions? */ + protected $flagRestorePermissions = false; + + /** @var AKAbstractPostproc Post processing class */ + protected $postProcEngine = null; + + /** @var string Absolute path to prepend to extracted files */ + protected $addPath = ''; + + /** @var array Which files to rename */ + public $renameFiles = array(); + + /** @var array Which directories to rename */ + public $renameDirs = array(); + + /** @var array Which files to skip */ + public $skipFiles = array(); + + /** @var integer Chunk size for processing */ + protected $chunkSize = 524288; + + /** @var resource File pointer to the current archive part file */ + protected $fp = null; + + /** @var int Run state when processing the current archive file */ + protected $runState = null; + + /** @var stdClass File header data, as read by the readFileHeader() method */ + protected $fileHeader = null; + + /** @var int How much of the uncompressed data we've read so far */ + protected $dataReadLength = 0; + + /** + * Public constructor + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Wakeup function, called whenever the class is unserialized + */ + public function __wakeup() + { + if($this->currentPartNumber >= 0) + { + $this->fp = @fopen($this->archiveList[$this->currentPartNumber], 'rb'); + if( (is_resource($this->fp)) && ($this->currentPartOffset > 0) ) + { + @fseek($this->fp, $this->currentPartOffset); + } + } + } + + /** + * Sleep function, called whenever the class is serialized + */ + public function shutdown() + { + if(is_resource($this->fp)) + { + $this->currentPartOffset = @ftell($this->fp); + @fclose($this->fp); + } + } + + /** + * Implements the abstract _prepare() method + */ + final protected function _prepare() + { + parent::__construct(); + + if( count($this->_parametersArray) > 0 ) + { + foreach($this->_parametersArray as $key => $value) + { + switch($key) + { + case 'filename': // Archive's absolute filename + $this->filename = $value; + break; + + case 'restore_permissions': // Should I restore permissions? + $this->flagRestorePermissions = $value; + break; + + case 'post_proc': // Should I use FTP? + $this->postProcEngine = AKFactory::getpostProc($value); + break; + + case 'add_path': // Path to prepend + $this->addPath = $value; + $this->addPath = str_replace('\\','/',$this->addPath); + $this->addPath = rtrim($this->addPath,'/'); + if(!empty($this->addPath)) $this->addPath .= '/'; + break; + + case 'rename_files': // Which files to rename (hash array) + $this->renameFiles = $value; + break; + + case 'rename_dirs': // Which files to rename (hash array) + $this->renameDirs = $value; + break; + + case 'skip_files': // Which files to skip (indexed array) + $this->skipFiles = $value; + break; + } + } + } + + $this->scanArchives(); + + $this->readArchiveHeader(); + $errMessage = $this->getError(); + if(!empty($errMessage)) + { + $this->setState('error', $errMessage); + } + else + { + $this->runState = AK_STATE_NOFILE; + $this->setState('prepared'); + } + } + + protected function _run() + { + if($this->getState() == 'postrun') return; + + $this->setState('running'); + + $timer = AKFactory::getTimer(); + + $status = true; + while( $status && ($timer->getTimeLeft() > 0) ) + { + switch( $this->runState ) + { + case AK_STATE_NOFILE: + $status = $this->readFileHeader(); + if($status) + { + // Send start of file notification + $message = new stdClass; + $message->type = 'startfile'; + $message->content = new stdClass; + if( array_key_exists('realfile', get_object_vars($this->fileHeader)) ) { + $message->content->realfile = $this->fileHeader->realFile; + } else { + $message->content->realfile = $this->fileHeader->file; + } + $message->content->file = $this->fileHeader->file; + if( array_key_exists('compressed', get_object_vars($this->fileHeader)) ) { + $message->content->compressed = $this->fileHeader->compressed; + } else { + $message->content->compressed = 0; + } + $message->content->uncompressed = $this->fileHeader->uncompressed; + $this->notify($message); + } + break; + + case AK_STATE_HEADER: + case AK_STATE_DATA: + $status = $this->processFileData(); + break; + + case AK_STATE_DATAREAD: + case AK_STATE_POSTPROC: + $this->postProcEngine->timestamp = $this->fileHeader->timestamp; + $status = $this->postProcEngine->process(); + $this->propagateFromObject( $this->postProcEngine ); + $this->runState = AK_STATE_DONE; + break; + + case AK_STATE_DONE: + default: + if($status) + { + // Send end of file notification + $message = new stdClass; + $message->type = 'endfile'; + $message->content = new stdClass; + if( array_key_exists('realfile', get_object_vars($this->fileHeader)) ) { + $message->content->realfile = $this->fileHeader->realFile; + } else { + $message->content->realfile = $this->fileHeader->file; + } + $message->content->file = $this->fileHeader->file; + if( array_key_exists('compressed', get_object_vars($this->fileHeader)) ) { + $message->content->compressed = $this->fileHeader->compressed; + } else { + $message->content->compressed = 0; + } + $message->content->uncompressed = $this->fileHeader->uncompressed; + $this->notify($message); + } + $this->runState = AK_STATE_NOFILE; + continue; + } + } + + $error = $this->getError(); + if( !$status && ($this->runState == AK_STATE_NOFILE) && empty( $error ) ) + { + // We just finished + $this->setState('postrun'); + } + elseif( !empty($error) ) + { + $this->setState( 'error', $error ); + } + } + + protected function _finalize() + { + // Nothing to do + $this->setState('finished'); + } + + /** + * Returns the base extension of the file, e.g. '.jpa' + * @return string + */ + private function getBaseExtension() + { + static $baseextension; + + if(empty($baseextension)) + { + $basename = basename($this->filename); + $lastdot = strrpos($basename,'.'); + $baseextension = substr($basename, $lastdot); + } + + return $baseextension; + } + + /** + * Scans for archive parts + */ + private function scanArchives() + { + $privateArchiveList = array(); + + // Get the components of the archive filename + $dirname = dirname($this->filename); + $base_extension = $this->getBaseExtension(); + $basename = basename($this->filename, $base_extension); + $this->totalSize = 0; + + // Scan for multiple parts until we don't find any more of them + $count = 0; + $found = true; + $this->archiveList = array(); + while($found) + { + ++$count; + $extension = substr($base_extension, 0, 2).sprintf('%02d', $count); + $filename = $dirname.DIRECTORY_SEPARATOR.$basename.$extension; + $found = file_exists($filename); + if($found) + { + // Add yet another part, with a numeric-appended filename + $this->archiveList[] = $filename; + + $filesize = @filesize($filename); + $this->totalSize += $filesize; + + $privateArchiveList[] = array($filename, $filesize); + } + else + { + // Add the last part, with the regular extension + $this->archiveList[] = $this->filename; + + $filename = $this->filename; + $filesize = @filesize($filename); + $this->totalSize += $filesize; + + $privateArchiveList[] = array($filename, $filesize); + } + } + + $this->currentPartNumber = -1; + $this->currentPartOffset = 0; + $this->runState = AK_STATE_NOFILE; + + // Send start of file notification + $message = new stdClass; + $message->type = 'totalsize'; + $message->content = new stdClass; + $message->content->totalsize = $this->totalSize; + $message->content->filelist = $privateArchiveList; + $this->notify($message); + } + + /** + * Opens the next part file for reading + */ + protected function nextFile() + { + ++$this->currentPartNumber; + + if( $this->currentPartNumber > (count($this->archiveList) - 1) ) + { + $this->setState('postrun'); + return false; + } + else + { + if( is_resource($this->fp) ) @fclose($this->fp); + $this->fp = @fopen( $this->archiveList[$this->currentPartNumber], 'rb' ); + fseek($this->fp, 0); + $this->currentPartOffset = 0; + return true; + } + } + + /** + * Returns true if we have reached the end of file + * @param $local bool True to return EOF of the local file, false (default) to return if we have reached the end of the archive set + * @return bool True if we have reached End Of File + */ + protected function isEOF($local = false) + { + $eof = @feof($this->fp); + + if(!$eof) + { + // Border case: right at the part's end (eeeek!!!). For the life of me, I don't understand why + // feof() doesn't report true. It expects the fp to be positioned *beyond* the EOF to report + // true. Incredible! :( + $position = @ftell($this->fp); + $filesize = @filesize( $this->archiveList[$this->currentPartNumber] ); + if( $position >= $filesize ) $eof = true; + } + + if($local) + { + return $eof; + } + else + { + return $eof && ($this->currentPartNumber >= (count($this->archiveList)-1) ); + } + } + + /** + * Tries to make a directory user-writable so that we can write a file to it + * @param $path string A path to a file + */ + protected function setCorrectPermissions($path) + { + static $rootDir = null; + + if(is_null($rootDir)) { + $rootDir = rtrim(AKFactory::get('kickstart.setup.destdir',''),'/\\'); + } + + $directory = rtrim(dirname($path),'/\\'); + if($directory != $rootDir) { + // Is this an unwritable directory? + if(!is_writeable($directory)) { + $this->postProcEngine->chmod( $directory, 0755 ); + } + } + $this->postProcEngine->chmod( $path, 0644 ); + } + + /** + * Concrete classes are supposed to use this method in order to read the archive's header and + * prepare themselves to the point of being ready to extract the first file. + */ + protected abstract function readArchiveHeader(); + + /** + * Concrete classes must use this method to read the file header + * @return bool True if reading the file was successful, false if an error occured or we reached end of archive + */ + protected abstract function readFileHeader(); + + /** + * Concrete classes must use this method to process file data. It must set $runState to AK_STATE_DATAREAD when + * it's finished processing the file data. + * @return bool True if processing the file data was successful, false if an error occured + */ + protected abstract function processFileData(); + + /** + * Reads data from the archive and notifies the observer with the 'reading' message + * @param $fp + * @param $length + */ + protected function fread($fp, $length = null) + { + if(is_numeric($length)) + { + if($length > 0) { + $data = fread($fp, $length); + } else { + $data = fread($fp); + } + } + else + { + $data = fread($fp); + } + if($data === false) $data = ''; + + // Send start of file notification + $message = new stdClass; + $message->type = 'reading'; + $message->content = new stdClass; + $message->content->length = strlen($data); + $this->notify($message); + + return $data; + } +} + +/** + * The superclass of all Akeeba Kickstart parts. The "parts" are intelligent stateful + * classes which perform a single procedure and have preparation, running and + * finalization phases. The transition between phases is handled automatically by + * this superclass' tick() final public method, which should be the ONLY public API + * exposed to the rest of the Akeeba Engine. + */ +abstract class AKAbstractPart extends AKAbstractObject +{ + /** + * Indicates whether this part has finished its initialisation cycle + * @var boolean + */ + protected $isPrepared = false; + + /** + * Indicates whether this part has more work to do (it's in running state) + * @var boolean + */ + protected $isRunning = false; + + /** + * Indicates whether this part has finished its finalization cycle + * @var boolean + */ + protected $isFinished = false; + + /** + * Indicates whether this part has finished its run cycle + * @var boolean + */ + protected $hasRan = false; + + /** + * The name of the engine part (a.k.a. Domain), used in return table + * generation. + * @var string + */ + protected $active_domain = ""; + + /** + * The step this engine part is in. Used verbatim in return table and + * should be set by the code in the _run() method. + * @var string + */ + protected $active_step = ""; + + /** + * A more detailed description of the step this engine part is in. Used + * verbatim in return table and should be set by the code in the _run() + * method. + * @var string + */ + protected $active_substep = ""; + + /** + * Any configuration variables, in the form of an array. + * @var array + */ + protected $_parametersArray = array(); + + /** @var string The database root key */ + protected $databaseRoot = array(); + + /** @var int Last reported warnings's position in array */ + private $warnings_pointer = -1; + + /** @var array An array of observers */ + protected $observers = array(); + + /** + * Runs the preparation for this part. Should set _isPrepared + * to true + */ + abstract protected function _prepare(); + + /** + * Runs the finalisation process for this part. Should set + * _isFinished to true. + */ + abstract protected function _finalize(); + + /** + * Runs the main functionality loop for this part. Upon calling, + * should set the _isRunning to true. When it finished, should set + * the _hasRan to true. If an error is encountered, setError should + * be used. + */ + abstract protected function _run(); + + /** + * Sets the BREAKFLAG, which instructs this engine part that the current step must break immediately, + * in fear of timing out. + */ + protected function setBreakFlag() + { + AKFactory::set('volatile.breakflag', true); + } + + /** + * Sets the engine part's internal state, in an easy to use manner + * + * @param string $state One of init, prepared, running, postrun, finished, error + * @param string $errorMessage The reported error message, should the state be set to error + */ + protected function setState($state = 'init', $errorMessage='Invalid setState argument') + { + switch($state) + { + case 'init': + $this->isPrepared = false; + $this->isRunning = false; + $this->isFinished = false; + $this->hasRun = false; + break; + + case 'prepared': + $this->isPrepared = true; + $this->isRunning = false; + $this->isFinished = false; + $this->hasRun = false; + break; + + case 'running': + $this->isPrepared = true; + $this->isRunning = true; + $this->isFinished = false; + $this->hasRun = false; + break; + + case 'postrun': + $this->isPrepared = true; + $this->isRunning = false; + $this->isFinished = false; + $this->hasRun = true; + break; + + case 'finished': + $this->isPrepared = true; + $this->isRunning = false; + $this->isFinished = true; + $this->hasRun = false; + break; + + case 'error': + default: + $this->setError($errorMessage); + break; + } + } + + /** + * The public interface to an engine part. This method takes care for + * calling the correct method in order to perform the initialisation - + * run - finalisation cycle of operation and return a proper reponse array. + * @return array A Reponse Array + */ + final public function tick() + { + // Call the right action method, depending on engine part state + switch( $this->getState() ) + { + case "init": + $this->_prepare(); + break; + case "prepared": + $this->_run(); + break; + case "running": + $this->_run(); + break; + case "postrun": + $this->_finalize(); + break; + } + + // Send a Return Table back to the caller + $out = $this->_makeReturnTable(); + return $out; + } + + /** + * Returns a copy of the class's status array + * @return array + */ + public function getStatusArray() + { + return $this->_makeReturnTable(); + } + + /** + * Sends any kind of setup information to the engine part. Using this, + * we avoid passing parameters to the constructor of the class. These + * parameters should be passed as an indexed array and should be taken + * into account during the preparation process only. This function will + * set the error flag if it's called after the engine part is prepared. + * + * @param array $parametersArray The parameters to be passed to the + * engine part. + */ + final public function setup( $parametersArray ) + { + if( $this->isPrepared ) + { + $this->setState('error', "Can't modify configuration after the preparation of " . $this->active_domain); + } + else + { + $this->_parametersArray = $parametersArray; + if(array_key_exists('root', $parametersArray)) + { + $this->databaseRoot = $parametersArray['root']; + } + } + } + + /** + * Returns the state of this engine part. + * + * @return string The state of this engine part. It can be one of + * error, init, prepared, running, postrun, finished. + */ + final public function getState() + { + if( $this->getError() ) + { + return "error"; + } + + if( !($this->isPrepared) ) + { + return "init"; + } + + if( !($this->isFinished) && !($this->isRunning) && !( $this->hasRun ) && ($this->isPrepared) ) + { + return "prepared"; + } + + if ( !($this->isFinished) && $this->isRunning && !( $this->hasRun ) ) + { + return "running"; + } + + if ( !($this->isFinished) && !($this->isRunning) && $this->hasRun ) + { + return "postrun"; + } + + if ( $this->isFinished ) + { + return "finished"; + } + } + + /** + * Constructs a Response Array based on the engine part's state. + * @return array The Response Array for the current state + */ + final protected function _makeReturnTable() + { + // Get a list of warnings + $warnings = $this->getWarnings(); + // Report only new warnings if there is no warnings queue size + if( $this->_warnings_queue_size == 0 ) + { + if( ($this->warnings_pointer > 0) && ($this->warnings_pointer < (count($warnings)) ) ) + { + $warnings = array_slice($warnings, $this->warnings_pointer + 1); + $this->warnings_pointer += count($warnings); + } + else + { + $this->warnings_pointer = count($warnings); + } + } + + $out = array( + 'HasRun' => (!($this->isFinished)), + 'Domain' => $this->active_domain, + 'Step' => $this->active_step, + 'Substep' => $this->active_substep, + 'Error' => $this->getError(), + 'Warnings' => $warnings + ); + + return $out; + } + + final protected function setDomain($new_domain) + { + $this->active_domain = $new_domain; + } + + final public function getDomain() + { + return $this->active_domain; + } + + final protected function setStep($new_step) + { + $this->active_step = $new_step; + } + + final public function getStep() + { + return $this->active_step; + } + + final protected function setSubstep($new_substep) + { + $this->active_substep = $new_substep; + } + + final public function getSubstep() + { + return $this->active_substep; + } + + /** + * Attaches an observer object + * @param AKAbstractPartObserver $obs + */ + function attach(AKAbstractPartObserver $obs) { + $this->observers["$obs"] = $obs; + } + + /** + * Dettaches an observer object + * @param AKAbstractPartObserver $obs + */ + function detach(AKAbstractPartObserver $obs) { + delete($this->observers["$obs"]); + } + + /** + * Notifies observers each time something interesting happened to the part + * @param mixed $message The event object + */ + protected function notify($message) { + foreach ($this->observers as $obs) { + $obs->update($this, $message); + } + } +} + +/** + * Descendants of this class can be used in the unarchiver's observer methods (attach, detach and notify) + * @author Nicholas + * + */ +abstract class AKAbstractPartObserver +{ + abstract public function update($object, $message); +} + +/** + * Direct file writer + */ +class AKPostprocDirect extends AKAbstractPostproc +{ + public function process() + { + $restorePerms = AKFactory::get('kickstart.setup.restoreperms', false); + if($restorePerms) + { + @chmod($this->filename, $this->perms); + } + else + { + if(@is_file($this->filename)) + { + @chmod($this->filename, 0644); + } + else + { + @chmod($this->filename, 0755); + } + } + if($this->timestamp > 0) + { + @touch($this->filename, $this->timestamp); + } + return true; + } + + public function processFilename($filename, $perms = 0755) + { + $this->perms = $perms; + $this->filename = $filename; + return $filename; + } + + public function createDirRecursive( $dirName, $perms ) + { + if( AKFactory::get('kickstart.setup.dryrun','0') ) return true; + if (@mkdir($dirName, 0755, true)) { + @chmod($dirName, 0755); + return true; + } + + $root = AKFactory::get('kickstart.setup.destdir'); + $root = rtrim(str_replace('\\','/',$root),'/'); + $dir = rtrim(str_replace('\\','/',$dirName),'/'); + if(strpos($dir, $root) === 0) { + $dir = ltrim(substr($dir, strlen($root)), '/'); + $root .= '/'; + } else { + $root = ''; + } + + if(empty($dir)) return true; + + $dirArray = explode('/', $dir); + $path = ''; + foreach( $dirArray as $dir ) + { + $path .= $dir . '/'; + $ret = is_dir($root.$path) ? true : @mkdir($root.$path); + if( !$ret ) { + // Is this a file instead of a directory? + if(is_file($root.$path) ) + { + @unlink($root.$path); + $ret = @mkdir($root.$path); + } + if( !$ret ) { + $this->setError( AKText::sprintf('COULDNT_CREATE_DIR',$path) ); + return false; + } + } + // Try to set new directory permissions to 0755 + @chmod($root.$path, $perms); + } + return true; + } + + public function chmod( $file, $perms ) + { + if( AKFactory::get('kickstart.setup.dryrun','0') ) return true; + + return @chmod( $file, $perms ); + } + + public function unlink( $file ) + { + return @unlink( $file ); + } + + public function rmdir( $directory ) + { + return @rmdir( $directory ); + } + + public function rename( $from, $to ) + { + return @rename($from, $to); + } + +} + +/** + * FTP file writer + */ +class AKPostprocFTP extends AKAbstractPostproc +{ + /** @var bool Should I use FTP over implicit SSL? */ + public $useSSL = false; + /** @var bool use Passive mode? */ + public $passive = true; + /** @var string FTP host name */ + public $host = ''; + /** @var int FTP port */ + public $port = 21; + /** @var string FTP user name */ + public $user = ''; + /** @var string FTP password */ + public $pass = ''; + /** @var string FTP initial directory */ + public $dir = ''; + /** @var resource The FTP handle */ + private $handle = null; + /** @var string The temporary directory where the data will be stored */ + private $tempDir = ''; + + public function __construct() + { + parent::__construct(); + + $this->useSSL = AKFactory::get('kickstart.ftp.ssl', false); + $this->passive = AKFactory::get('kickstart.ftp.passive', true); + $this->host = AKFactory::get('kickstart.ftp.host', ''); + $this->port = AKFactory::get('kickstart.ftp.port', 21); + if(trim($this->port) == '') $this->port = 21; + $this->user = AKFactory::get('kickstart.ftp.user', ''); + $this->pass = AKFactory::get('kickstart.ftp.pass', ''); + $this->dir = AKFactory::get('kickstart.ftp.dir', ''); + $this->tempDir = AKFactory::get('kickstart.ftp.tempdir', ''); + + $connected = $this->connect(); + + if($connected) + { + if(!empty($this->tempDir)) + { + $tempDir = rtrim($this->tempDir, '/\\').'/'; + $writable = $this->isDirWritable($tempDir); + } + else + { + $tempDir = ''; + $writable = false; + } + + if(!$writable) { + // Default temporary directory is the current root + $tempDir = function_exists('getcwd') ? getcwd() : dirname(__FILE__); + if(empty($tempDir)) + { + // Oh, we have no directory reported! + $tempDir = '.'; + } + $absoluteDirToHere = $tempDir; + $tempDir = rtrim(str_replace('\\','/',$tempDir),'/'); + if(!empty($tempDir)) $tempDir .= '/'; + $this->tempDir = $tempDir; + // Is this directory writable? + $writable = $this->isDirWritable($tempDir); + } + + if(!$writable) + { + // Nope. Let's try creating a temporary directory in the site's root. + $tempDir = $absoluteDirToHere.'/kicktemp'; + $this->createDirRecursive($tempDir, 0777); + // Try making it writable... + $this->fixPermissions($tempDir); + $writable = $this->isDirWritable($tempDir); + } + + // Was the new directory writable? + if(!$writable) + { + // Let's see if the user has specified one + $userdir = AKFactory::get('kickstart.ftp.tempdir', ''); + if(!empty($userdir)) + { + // Is it an absolute or a relative directory? + $absolute = false; + $absolute = $absolute || ( substr($userdir,0,1) == '/' ); + $absolute = $absolute || ( substr($userdir,1,1) == ':' ); + $absolute = $absolute || ( substr($userdir,2,1) == ':' ); + if(!$absolute) + { + // Make absolute + $tempDir = $absoluteDirToHere.$userdir; + } + else + { + // it's already absolute + $tempDir = $userdir; + } + // Does the directory exist? + if( is_dir($tempDir) ) + { + // Yeah. Is it writable? + $writable = $this->isDirWritable($tempDir); + } + } + } + $this->tempDir = $tempDir; + + if(!$writable) + { + // No writable directory found!!! + $this->setError(AKText::_('FTP_TEMPDIR_NOT_WRITABLE')); + } + else + { + AKFactory::set('kickstart.ftp.tempdir', $tempDir); + $this->tempDir = $tempDir; + } + } + } + + function __wakeup() + { + $this->connect(); + } + + public function connect() + { + // Connect to server, using SSL if so required + if($this->useSSL) { + $this->handle = @ftp_ssl_connect($this->host, $this->port); + } else { + $this->handle = @ftp_connect($this->host, $this->port); + } + if($this->handle === false) + { + $this->setError(AKText::_('WRONG_FTP_HOST')); + return false; + } + + // Login + if(! @ftp_login($this->handle, $this->user, $this->pass)) + { + $this->setError(AKText::_('WRONG_FTP_USER')); + @ftp_close($this->handle); + return false; + } + + // Change to initial directory + if(! @ftp_chdir($this->handle, $this->dir)) + { + $this->setError(AKText::_('WRONG_FTP_PATH1')); + @ftp_close($this->handle); + return false; + } + + // Enable passive mode if the user requested it + if( $this->passive ) + { + @ftp_pasv($this->handle, true); + } + else + { + @ftp_pasv($this->handle, false); + } + + return true; + } + + public function process() + { + if( is_null($this->tempFilename) ) + { + // If an empty filename is passed, it means that we shouldn't do any post processing, i.e. + // the entity was a directory or symlink + return true; + } + + $remotePath = dirname($this->filename); + $removePath = AKFactory::get('kickstart.setup.destdir',''); + if(!empty($removePath)) + { + $removePath = ltrim($removePath, "/"); + $remotePath = ltrim($remotePath, "/"); + $left = substr($remotePath, 0, strlen($removePath)); + if($left == $removePath) + { + $remotePath = substr($remotePath, strlen($removePath)); + } + } + + $absoluteFSPath = dirname($this->filename); + $relativeFTPPath = trim($remotePath, '/'); + $absoluteFTPPath = '/'.trim( $this->dir, '/' ).'/'.trim($remotePath, '/'); + $onlyFilename = basename($this->filename); + + $remoteName = $absoluteFTPPath.'/'.$onlyFilename; + + $ret = @ftp_chdir($this->handle, $absoluteFTPPath); + if($ret === false) + { + $ret = $this->createDirRecursive( $absoluteFSPath, 0755); + if($ret === false) { + $this->setError(AKText::sprintf('FTP_COULDNT_UPLOAD', $this->filename)); + return false; + } + $ret = @ftp_chdir($this->handle, $absoluteFTPPath); + if($ret === false) { + $this->setError(AKText::sprintf('FTP_COULDNT_UPLOAD', $this->filename)); + return false; + } + } + + $ret = @ftp_put($this->handle, $remoteName, $this->tempFilename, FTP_BINARY); + if($ret === false) + { + // If we couldn't create the file, attempt to fix the permissions in the PHP level and retry! + $this->fixPermissions($this->filename); + $this->unlink($this->filename); + + $fp = @fopen($this->tempFilename); + if($fp !== false) + { + $ret = @ftp_fput($this->handle, $remoteName, $fp, FTP_BINARY); + @fclose($fp); + } + else + { + $ret = false; + } + } + @unlink($this->tempFilename); + + if($ret === false) + { + $this->setError(AKText::sprintf('FTP_COULDNT_UPLOAD', $this->filename)); + return false; + } + $restorePerms = AKFactory::get('kickstart.setup.restoreperms', false); + if($restorePerms) + { + @ftp_chmod($this->_handle, $perms, $remoteName); + } + else + { + @ftp_chmod($this->_handle, 0644, $remoteName); + } + return true; + } + + public function processFilename($filename, $perms = 0755) + { + // Catch some error conditions... + if($this->getError()) + { + return false; + } + + // If a null filename is passed, it means that we shouldn't do any post processing, i.e. + // the entity was a directory or symlink + if(is_null($filename)) + { + $this->filename = null; + $this->tempFilename = null; + return null; + } + + // Strip absolute filesystem path to website's root + $removePath = AKFactory::get('kickstart.setup.destdir',''); + if(!empty($removePath)) + { + $left = substr($filename, 0, strlen($removePath)); + if($left == $removePath) + { + $filename = substr($filename, strlen($removePath)); + } + } + + // Trim slash on the left + $filename = ltrim($filename, '/'); + + $this->filename = $filename; + $this->tempFilename = tempnam($this->tempDir, 'kickstart-'); + $this->perms = $perms; + + if( empty($this->tempFilename) ) + { + // Oops! Let's try something different + $this->tempFilename = $this->tempDir.'/kickstart-'.time().'.dat'; + } + + return $this->tempFilename; + } + + private function isDirWritable($dir) + { + $fp = @fopen($dir.'/kickstart.dat', 'wb'); + if($fp === false) + { + return false; + } + else + { + @fclose($fp); + unlink($dir.'/kickstart.dat'); + return true; + } + } + + public function createDirRecursive( $dirName, $perms ) + { + // Strip absolute filesystem path to website's root + $removePath = AKFactory::get('kickstart.setup.destdir',''); + if(!empty($removePath)) + { + // UNIXize the paths + $removePath = str_replace('\\','/',$removePath); + $dirName = str_replace('\\','/',$dirName); + // Make sure they both end in a slash + $removePath = rtrim($removePath,'/\\').'/'; + $dirName = rtrim($dirName,'/\\').'/'; + // Process the path removal + $left = substr($dirName, 0, strlen($removePath)); + if($left == $removePath) + { + $dirName = substr($dirName, strlen($removePath)); + } + } + if(empty($dirName)) $dirName = ''; // 'cause the substr() above may return FALSE. + + $check = '/'.trim($this->dir,'/').'/'.trim($dirName, '/'); + if($this->is_dir($check)) return true; + + $alldirs = explode('/', $dirName); + $previousDir = '/'.trim($this->dir); + foreach($alldirs as $curdir) + { + $check = $previousDir.'/'.$curdir; + if(!$this->is_dir($check)) + { + // Proactively try to delete a file by the same name + @ftp_delete($this->handle, $check); + + if(@ftp_mkdir($this->handle, $check) === false) + { + // If we couldn't create the directory, attempt to fix the permissions in the PHP level and retry! + $this->fixPermissions($removePath.$check); + if(@ftp_mkdir($this->handle, $check) === false) + { + // Can we fall back to pure PHP mode, sire? + if(!@mkdir($check)) + { + $this->setError(AKText::sprintf('FTP_CANT_CREATE_DIR',$dir)); + return false; + } + else + { + // Since the directory was built by PHP, change its permissions + @chmod($check, "0777"); + return true; + } + } + } + @ftp_chmod($this->handle, $perms, $check); + } + $previousDir = $check; + } + + return true; + } + + public function close() + { + @ftp_close($this->handle); + } + + /* + * Tries to fix directory/file permissions in the PHP level, so that + * the FTP operation doesn't fail. + * @param $path string The full path to a directory or file + */ + private function fixPermissions( $path ) + { + // Turn off error reporting + if(!defined('KSDEBUG')) { + $oldErrorReporting = @error_reporting(E_NONE); + } + + // Get UNIX style paths + $relPath = str_replace('\\','/',$path); + $basePath = rtrim(str_replace('\\','/',dirname(__FILE__)),'/'); + $basePath = rtrim($basePath,'/'); + if(!empty($basePath)) $basePath .= '/'; + // Remove the leading relative root + if( substr($relPath,0,strlen($basePath)) == $basePath ) + $relPath = substr($relPath,strlen($basePath)); + $dirArray = explode('/', $relPath); + $pathBuilt = rtrim($basePath,'/'); + foreach( $dirArray as $dir ) + { + if(empty($dir)) continue; + $oldPath = $pathBuilt; + $pathBuilt .= '/'.$dir; + if(is_dir($oldPath.$dir)) + { + @chmod($oldPath.$dir, 0777); + } + else + { + if(@chmod($oldPath.$dir, 0777) === false) + { + @unlink($oldPath.$dir); + } + } + } + + // Restore error reporting + if(!defined('KSDEBUG')) { + @error_reporting($oldErrorReporting); + } + } + + public function chmod( $file, $perms ) + { + return @ftp_chmod($this->handle, $perms, $path); + } + + private function is_dir( $dir ) + { + return @ftp_chdir( $this->handle, $dir ); + } + + public function unlink( $file ) + { + $removePath = AKFactory::get('kickstart.setup.destdir',''); + if(!empty($removePath)) + { + $left = substr($file, 0, strlen($removePath)); + if($left == $removePath) + { + $file = substr($file, strlen($removePath)); + } + } + + $check = '/'.trim($this->dir,'/').'/'.trim($file, '/'); + + return @ftp_delete( $this->handle, $check ); + } + + public function rmdir( $directory ) + { + $removePath = AKFactory::get('kickstart.setup.destdir',''); + if(!empty($removePath)) + { + $left = substr($directory, 0, strlen($removePath)); + if($left == $removePath) + { + $directory = substr($directory, strlen($removePath)); + } + } + + $check = '/'.trim($this->dir,'/').'/'.trim($directory, '/'); + + return @ftp_rmdir( $this->handle, $check ); + } + + public function rename( $from, $to ) + { + $originalFrom = $from; + $originalTo = $to; + + $removePath = AKFactory::get('kickstart.setup.destdir',''); + if(!empty($removePath)) + { + $left = substr($from, 0, strlen($removePath)); + if($left == $removePath) + { + $from = substr($from, strlen($removePath)); + } + } + $from = '/'.trim($this->dir,'/').'/'.trim($from, '/'); + + if(!empty($removePath)) + { + $left = substr($to, 0, strlen($removePath)); + if($left == $removePath) + { + $to = substr($to, strlen($removePath)); + } + } + $to = '/'.trim($this->dir,'/').'/'.trim($to, '/'); + + $result = @ftp_rename( $this->handle, $from, $to ); + if($result !== true) + { + return @rename($from, $to); + } + else + { + return true; + } + } + +} + +/** + * JPA archive extraction class + */ +class AKUnarchiverJPA extends AKAbstractUnarchiver +{ + private $archiveHeaderData = array(); + + protected function readArchiveHeader() + { + // Initialize header data array + $this->archiveHeaderData = new stdClass(); + + // Open the first part + $this->nextFile(); + + // Fail for unreadable files + if( $this->fp === false ) return false; + + // Read the signature + $sig = fread( $this->fp, 3 ); + + if ($sig != 'JPA') + { + // Not a JPA file + $this->setError( AKText::_('ERR_NOT_A_JPA_FILE') ); + return false; + } + + // Read and parse header length + $header_length_array = unpack( 'v', fread( $this->fp, 2 ) ); + $header_length = $header_length_array[1]; + + // Read and parse the known portion of header data (14 bytes) + $bin_data = fread($this->fp, 14); + $header_data = unpack('Cmajor/Cminor/Vcount/Vuncsize/Vcsize', $bin_data); + + // Load any remaining header data (forward compatibility) + $rest_length = $header_length - 19; + if( $rest_length > 0 ) + $junk = fread($this->fp, $rest_length); + else + $junk = ''; + + // Temporary array with all the data we read + $temp = array( + 'signature' => $sig, + 'length' => $header_length, + 'major' => $header_data['major'], + 'minor' => $header_data['minor'], + 'filecount' => $header_data['count'], + 'uncompressedsize' => $header_data['uncsize'], + 'compressedsize' => $header_data['csize'], + 'unknowndata' => $junk + ); + // Array-to-object conversion + foreach($temp as $key => $value) + { + $this->archiveHeaderData->{$key} = $value; + } + + $this->currentPartOffset = @ftell($this->fp); + + $this->dataReadLength = 0; + + return true; + } + + /** + * Concrete classes must use this method to read the file header + * @return bool True if reading the file was successful, false if an error occured or we reached end of archive + */ + protected function readFileHeader() + { + // If the current part is over, proceed to the next part please + if( $this->isEOF(true) ) { + $this->nextFile(); + } + + // Get and decode Entity Description Block + $signature = fread($this->fp, 3); + + $this->fileHeader = new stdClass(); + $this->fileHeader->timestamp = 0; + + // Check signature + if( $signature != 'JPF' ) + { + if($this->isEOF(true)) + { + // This file is finished; make sure it's the last one + $this->nextFile(); + if(!$this->isEOF(false)) + { + $this->setError(AKText::sprintf('INVALID_FILE_HEADER', $this->currentPartNumber, $this->currentPartOffset)); + return false; + } + // We're just finished + return false; + } + else + { + // This is not a file block! The archive is corrupt. + $this->setError(AKText::sprintf('INVALID_FILE_HEADER', $this->currentPartNumber, $this->currentPartOffset)); + return false; + } + } + // This a JPA Entity Block. Process the header. + + $isBannedFile = false; + + // Read length of EDB and of the Entity Path Data + $length_array = unpack('vblocksize/vpathsize', fread($this->fp, 4)); + // Read the path data + if($length_array['pathsize'] > 0) { + $file = fread( $this->fp, $length_array['pathsize'] ); + } else { + $file = ''; + } + + // Handle file renaming + $isRenamed = false; + if(is_array($this->renameFiles) && (count($this->renameFiles) > 0) ) + { + if(array_key_exists($file, $this->renameFiles)) + { + $file = $this->renameFiles[$file]; + $isRenamed = true; + } + } + + // Handle directory renaming + $isDirRenamed = false; + if(is_array($this->renameDirs) && (count($this->renameDirs) > 0)) { + if(array_key_exists(dirname($file), $this->renameDirs)) { + $file = rtrim($this->renameDirs[dirname($file)],'/').'/'.basename($file); + $isRenamed = true; + $isDirRenamed = true; + } + } + + // Read and parse the known data portion + $bin_data = fread( $this->fp, 14 ); + $header_data = unpack('Ctype/Ccompression/Vcompsize/Vuncompsize/Vperms', $bin_data); + // Read any unknown data + $restBytes = $length_array['blocksize'] - (21 + $length_array['pathsize']); + if( $restBytes > 0 ) + { + // Start reading the extra fields + while($restBytes >= 4) + { + $extra_header_data = fread($this->fp, 4); + $extra_header = unpack('vsignature/vlength', $extra_header_data); + $restBytes -= 4; + $extra_header['length'] -= 4; + switch($extra_header['signature']) + { + case 256: + // File modified timestamp + if($extra_header['length'] > 0) + { + $bindata = fread($this->fp, $extra_header['length']); + $restBytes -= $extra_header['length']; + $timestamps = unpack('Vmodified', substr($bindata,0,4)); + $filectime = $timestamps['modified']; + $this->fileHeader->timestamp = $filectime; + } + break; + + default: + // Unknown field + if($extra_header['length']>0) { + $junk = fread($this->fp, $extra_header['length']); + $restBytes -= $extra_header['length']; + } + break; + } + } + if($restBytes > 0) $junk = fread($this->fp, $restBytes); + } + + $compressionType = $header_data['compression']; + + // Populate the return array + $this->fileHeader->file = $file; + $this->fileHeader->compressed = $header_data['compsize']; + $this->fileHeader->uncompressed = $header_data['uncompsize']; + switch($header_data['type']) + { + case 0: + $this->fileHeader->type = 'dir'; + break; + + case 1: + $this->fileHeader->type = 'file'; + break; + + case 2: + $this->fileHeader->type = 'link'; + break; + } + switch( $compressionType ) + { + case 0: + $this->fileHeader->compression = 'none'; + break; + case 1: + $this->fileHeader->compression = 'gzip'; + break; + case 2: + $this->fileHeader->compression = 'bzip2'; + break; + } + $this->fileHeader->permissions = $header_data['perms']; + + // Find hard-coded banned files + if( (basename($this->fileHeader->file) == ".") || (basename($this->fileHeader->file) == "..") ) + { + $isBannedFile = true; + } + + // Also try to find banned files passed in class configuration + if((count($this->skipFiles) > 0) && (!$isRenamed) ) + { + if(in_array($this->fileHeader->file, $this->skipFiles)) + { + $isBannedFile = true; + } + } + + // If we have a banned file, let's skip it + if($isBannedFile) + { + // Advance the file pointer, skipping exactly the size of the compressed data + $seekleft = $this->fileHeader->compressed; + while($seekleft > 0) + { + // Ensure that we can seek past archive part boundaries + $curSize = @filesize($this->archiveList[$this->currentPartNumber]); + $curPos = @ftell($this->fp); + $canSeek = $curSize - $curPos; + if($canSeek > $seekleft) $canSeek = $seekleft; + @fseek( $this->fp, $canSeek, SEEK_CUR ); + $seekleft -= $canSeek; + if($seekleft) $this->nextFile(); + } + + $this->currentPartOffset = @ftell($this->fp); + $this->runState = AK_STATE_DONE; + return true; + } + + // Last chance to prepend a path to the filename + if(!empty($this->addPath) && !$isDirRenamed) + { + $this->fileHeader->file = $this->addPath.$this->fileHeader->file; + } + + // Get the translated path name + $restorePerms = AKFactory::get('kickstart.setup.restoreperms', false); + if($this->fileHeader->type == 'file') + { + // Regular file; ask the postproc engine to process its filename + if($restorePerms) + { + $this->fileHeader->realFile = $this->postProcEngine->processFilename( $this->fileHeader->file, $this->fileHeader->permissions ); + } + else + { + $this->fileHeader->realFile = $this->postProcEngine->processFilename( $this->fileHeader->file ); + } + } + elseif($this->fileHeader->type == 'dir') + { + $dir = $this->fileHeader->file; + + // Directory; just create it + if($restorePerms) + { + $this->postProcEngine->createDirRecursive( $this->fileHeader->file, $this->fileHeader->permissions ); + } + else + { + $this->postProcEngine->createDirRecursive( $this->fileHeader->file, 0755 ); + } + $this->postProcEngine->processFilename(null); + } + else + { + // Symlink; do not post-process + $this->postProcEngine->processFilename(null); + } + + $this->createDirectory(); + + // Header is read + $this->runState = AK_STATE_HEADER; + + $this->dataReadLength = 0; + + return true; + } + + /** + * Concrete classes must use this method to process file data. It must set $runState to AK_STATE_DATAREAD when + * it's finished processing the file data. + * @return bool True if processing the file data was successful, false if an error occured + */ + protected function processFileData() + { + switch( $this->fileHeader->type ) + { + case 'dir': + return $this->processTypeDir(); + break; + + case 'link': + return $this->processTypeLink(); + break; + + case 'file': + switch($this->fileHeader->compression) + { + case 'none': + return $this->processTypeFileUncompressed(); + break; + + case 'gzip': + case 'bzip2': + return $this->processTypeFileCompressedSimple(); + break; + + } + break; + } + } + + private function processTypeFileUncompressed() + { + // Uncompressed files are being processed in small chunks, to avoid timeouts + if( ($this->dataReadLength == 0) && !AKFactory::get('kickstart.setup.dryrun','0') ) + { + // Before processing file data, ensure permissions are adequate + $this->setCorrectPermissions( $this->fileHeader->file ); + } + + // Open the output file + if( !AKFactory::get('kickstart.setup.dryrun','0') ) + { + $ignore = AKFactory::get('kickstart.setup.ignoreerrors', false); + if ($this->dataReadLength == 0) { + $outfp = @fopen( $this->fileHeader->realFile, 'wb' ); + } else { + $outfp = @fopen( $this->fileHeader->realFile, 'ab' ); + } + + // Can we write to the file? + if( ($outfp === false) && (!$ignore) ) { + // An error occured + $this->setError( AKText::sprintf('COULDNT_WRITE_FILE', $this->fileHeader->realFile) ); + return false; + } + } + + // Does the file have any data, at all? + if( $this->fileHeader->compressed == 0 ) + { + // No file data! + if( !AKFactory::get('kickstart.setup.dryrun','0') && is_resource($outfp) ) @fclose($outfp); + $this->runState = AK_STATE_DATAREAD; + return true; + } + + // Reference to the global timer + $timer = AKFactory::getTimer(); + + $toReadBytes = 0; + $leftBytes = $this->fileHeader->compressed - $this->dataReadLength; + + // Loop while there's data to read and enough time to do it + while( ($leftBytes > 0) && ($timer->getTimeLeft() > 0) ) + { + $toReadBytes = ($leftBytes > $this->chunkSize) ? $this->chunkSize : $leftBytes; + $data = $this->fread( $this->fp, $toReadBytes ); + $reallyReadBytes = akstringlen($data); + $leftBytes -= $reallyReadBytes; + $this->dataReadLength += $reallyReadBytes; + if($reallyReadBytes < $toReadBytes) + { + // We read less than requested! Why? Did we hit local EOF? + if( $this->isEOF(true) && !$this->isEOF(false) ) + { + // Yeap. Let's go to the next file + $this->nextFile(); + } + else + { + // Nope. The archive is corrupt + $this->setError( AKText::_('ERR_CORRUPT_ARCHIVE') ); + return false; + } + } + if( !AKFactory::get('kickstart.setup.dryrun','0') ) + if(is_resource($outfp)) @fwrite( $outfp, $data ); + } + + // Close the file pointer + if( !AKFactory::get('kickstart.setup.dryrun','0') ) + if(is_resource($outfp)) @fclose($outfp); + + // Was this a pre-timeout bail out? + if( $leftBytes > 0 ) + { + $this->runState = AK_STATE_DATA; + } + else + { + // Oh! We just finished! + $this->runState = AK_STATE_DATAREAD; + $this->dataReadLength = 0; + } + + return true; + } + + private function processTypeFileCompressedSimple() + { + if( !AKFactory::get('kickstart.setup.dryrun','0') ) + { + // Before processing file data, ensure permissions are adequate + $this->setCorrectPermissions( $this->fileHeader->file ); + + // Open the output file + $outfp = @fopen( $this->fileHeader->realFile, 'wb' ); + + // Can we write to the file? + $ignore = AKFactory::get('kickstart.setup.ignoreerrors', false); + if( ($outfp === false) && (!$ignore) ) { + // An error occured + $this->setError( AKText::sprintf('COULDNT_WRITE_FILE', $this->fileHeader->realFile) ); + return false; + } + } + + // Does the file have any data, at all? + if( $this->fileHeader->compressed == 0 ) + { + // No file data! + if( !AKFactory::get('kickstart.setup.dryrun','0') ) + if(is_resource($outfp)) @fclose($outfp); + $this->runState = AK_STATE_DATAREAD; + return true; + } + + // Simple compressed files are processed as a whole; we can't do chunk processing + $zipData = $this->fread( $this->fp, $this->fileHeader->compressed ); + while( akstringlen($zipData) < $this->fileHeader->compressed ) + { + // End of local file before reading all data, but have more archive parts? + if($this->isEOF(true) && !$this->isEOF(false)) + { + // Yeap. Read from the next file + $this->nextFile(); + $bytes_left = $this->fileHeader->compressed - akstringlen($zipData); + $zipData .= $this->fread( $this->fp, $bytes_left ); + } + else + { + $this->setError( AKText::_('ERR_CORRUPT_ARCHIVE') ); + return false; + } + } + + if($this->fileHeader->compression == 'gzip') + { + $unzipData = gzinflate( $zipData ); + } + elseif($this->fileHeader->compression == 'bzip2') + { + $unzipData = bzdecompress( $zipData ); + } + unset($zipData); + + // Write to the file. + if( !AKFactory::get('kickstart.setup.dryrun','0') && is_resource($outfp) ) + { + @fwrite( $outfp, $unzipData, $this->fileHeader->uncompressed ); + @fclose( $outfp ); + } + unset($unzipData); + + $this->runState = AK_STATE_DATAREAD; + return true; + } + + /** + * Process the file data of a link entry + * @return bool + */ + private function processTypeLink() + { + $readBytes = 0; + $toReadBytes = 0; + $leftBytes = $this->fileHeader->compressed; + $data = ''; + + while( $leftBytes > 0) + { + $toReadBytes = ($leftBytes > $this->chunkSize) ? $this->chunkSize : $leftBytes; + $mydata = $this->fread( $this->fp, $toReadBytes ); + $reallyReadBytes = akstringlen($mydata); + $data .= $mydata; + $leftBytes -= $reallyReadBytes; + if($reallyReadBytes < $toReadBytes) + { + // We read less than requested! Why? Did we hit local EOF? + if( $this->isEOF(true) && !$this->isEOF(false) ) + { + // Yeap. Let's go to the next file + $this->nextFile(); + } + else + { + // Nope. The archive is corrupt + $this->setError( AKText::_('ERR_CORRUPT_ARCHIVE') ); + return false; + } + } + } + + // Try to remove an existing file or directory by the same name + if(file_exists($this->fileHeader->realFile)) { @unlink($this->fileHeader->realFile); @rmdir($this->fileHeader->realFile); } + // Remove any trailing slash + if(substr($this->fileHeader->realFile, -1) == '/') $this->fileHeader->realFile = substr($this->fileHeader->realFile, 0, -1); + // Create the symlink - only possible within PHP context. There's no support built in the FTP protocol, so no postproc use is possible here :( + if( !AKFactory::get('kickstart.setup.dryrun','0') ) + @symlink($data, $this->fileHeader->realFile); + + $this->runState = AK_STATE_DATAREAD; + + return true; // No matter if the link was created! + } + + /** + * Process the file data of a directory entry + * @return bool + */ + private function processTypeDir() + { + // Directory entries in the JPA do not have file data, therefore we're done processing the entry + $this->runState = AK_STATE_DATAREAD; + return true; + } + + /** + * Creates the directory this file points to + */ + protected function createDirectory() + { + if( AKFactory::get('kickstart.setup.dryrun','0') ) return true; + + // Do we need to create a directory? + if(empty($this->fileHeader->realFile)) $this->fileHeader->realFile = $this->fileHeader->file; + $lastSlash = strrpos($this->fileHeader->realFile, '/'); + $dirName = substr( $this->fileHeader->realFile, 0, $lastSlash); + $perms = $this->flagRestorePermissions ? $retArray['permissions'] : 0755; + $ignore = AKFactory::get('kickstart.setup.ignoreerrors', false); + if( ($this->postProcEngine->createDirRecursive($dirName, $perms) == false) && (!$ignore) ) { + $this->setError( AKText::sprintf('COULDNT_CREATE_DIR', $dirName) ); + return false; + } + else + { + return true; + } + } +} + +/** + * ZIP archive extraction class + * + * Since the file data portion of ZIP and JPA are similarly structured (it's empty for dirs, + * linked node name for symlinks, dumped binary data for no compressions and dumped gzipped + * binary data for gzip compression) we just have to subclass AKUnarchiverJPA and change the + * header reading bits. Reusable code ;) + */ +class AKUnarchiverZIP extends AKUnarchiverJPA +{ + var $expectDataDescriptor = false; + + protected function readArchiveHeader() + { + // Initialize header data array + $this->archiveHeaderData = new stdClass(); + + // Open the first part + $this->nextFile(); + + // Fail for unreadable files + if( $this->fp === false ) return false; + + // Read a possible multipart signature + $sigBinary = fread( $this->fp, 4 ); + $headerData = unpack('Vsig', $sigBinary); + + // Roll back if it's not a multipart archive + if( $headerData['sig'] == 0x04034b50 ) fseek($this->fp, -4, SEEK_CUR); + + $multiPartSigs = array( + 0x08074b50, // Multi-part ZIP + 0x30304b50, // Multi-part ZIP (alternate) + 0x04034b50 // Single file + ); + if( !in_array($headerData['sig'], $multiPartSigs) ) + { + $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE')); + return false; + } + + $this->currentPartOffset = @ftell($this->fp); + + $this->dataReadLength = 0; + + return true; + } + + /** + * Concrete classes must use this method to read the file header + * @return bool True if reading the file was successful, false if an error occured or we reached end of archive + */ + protected function readFileHeader() + { + // If the current part is over, proceed to the next part please + if( $this->isEOF(true) ) { + $this->nextFile(); + } + + if($this->expectDataDescriptor) + { + // The last file had bit 3 of the general purpose bit flag set. This means that we have a + // 12 byte data descriptor we need to skip. To make things worse, there might also be a 4 + // byte optional data descriptor header (0x08074b50). + $junk = @fread($this->fp, 4); + $junk = unpack('Vsig', $junk); + if($junk['sig'] == 0x08074b50) { + // Yes, there was a signature + $junk = @fread($this->fp, 12); + if(defined('KSDEBUG')) { + debugMsg('Data descriptor (w/ header) skipped at '.(ftell($this->fp)-12)); + } + } else { + // No, there was no signature, just read another 8 bytes + $junk = @fread($this->fp, 8); + if(defined('KSDEBUG')) { + debugMsg('Data descriptor (w/out header) skipped at '.(ftell($this->fp)-8)); + } + } + + // And check for EOF, too + if( $this->isEOF(true) ) { + if(defined('KSDEBUG')) { + debugMsg('EOF before reading header'); + } + + $this->nextFile(); + } + } + + // Get and decode Local File Header + $headerBinary = fread($this->fp, 30); + $headerData = unpack('Vsig/C2ver/vbitflag/vcompmethod/vlastmodtime/vlastmoddate/Vcrc/Vcompsize/Vuncomp/vfnamelen/veflen', $headerBinary); + + // Check signature + if(!( $headerData['sig'] == 0x04034b50 )) + { + if(defined('KSDEBUG')) { + debugMsg('Not a file signature at '.(ftell($this->fp)-4)); + } + + // The signature is not the one used for files. Is this a central directory record (i.e. we're done)? + if($headerData['sig'] == 0x02014b50) + { + if(defined('KSDEBUG')) { + debugMsg('EOCD signature at '.(ftell($this->fp)-4)); + } + // End of ZIP file detected. We'll just skip to the end of file... + while( $this->nextFile() ) {}; + @fseek($this->fp, 0, SEEK_END); // Go to EOF + return false; + } + else + { + if(defined('KSDEBUG')) { + debugMsg( 'Invalid signature ' . dechex($headerData['sig']) . ' at '.ftell($this->fp) ); + } + $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE')); + return false; + } + } + + // If bit 3 of the bitflag is set, expectDataDescriptor is true + $this->expectDataDescriptor = ($headerData['bitflag'] & 4) == 4; + + $this->fileHeader = new stdClass(); + $this->fileHeader->timestamp = 0; + + // Read the last modified data and time + $lastmodtime = $headerData['lastmodtime']; + $lastmoddate = $headerData['lastmoddate']; + + if($lastmoddate && $lastmodtime) + { + // ----- Extract time + $v_hour = ($lastmodtime & 0xF800) >> 11; + $v_minute = ($lastmodtime & 0x07E0) >> 5; + $v_seconde = ($lastmodtime & 0x001F)*2; + + // ----- Extract date + $v_year = (($lastmoddate & 0xFE00) >> 9) + 1980; + $v_month = ($lastmoddate & 0x01E0) >> 5; + $v_day = $lastmoddate & 0x001F; + + // ----- Get UNIX date format + $this->fileHeader->timestamp = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + } + + $isBannedFile = false; + + $this->fileHeader->compressed = $headerData['compsize']; + $this->fileHeader->uncompressed = $headerData['uncomp']; + $nameFieldLength = $headerData['fnamelen']; + $extraFieldLength = $headerData['eflen']; + + // Read filename field + $this->fileHeader->file = fread( $this->fp, $nameFieldLength ); + + // Handle file renaming + $isRenamed = false; + if(is_array($this->renameFiles) && (count($this->renameFiles) > 0) ) + { + if(array_key_exists($this->fileHeader->file, $this->renameFiles)) + { + $this->fileHeader->file = $this->renameFiles[$this->fileHeader->file]; + $isRenamed = true; + } + } + + // Handle directory renaming + $isDirRenamed = false; + if(is_array($this->renameDirs) && (count($this->renameDirs) > 0)) { + if(array_key_exists(dirname($file), $this->renameDirs)) { + $file = rtrim($this->renameDirs[dirname($file)],'/').'/'.basename($file); + $isRenamed = true; + $isDirRenamed = true; + } + } + + // Read extra field if present + if($extraFieldLength > 0) { + $extrafield = fread( $this->fp, $extraFieldLength ); + } + + if(defined('KSDEBUG')) { + debugMsg( '*'.ftell($this->fp).' IS START OF '.$this->fileHeader->file. ' ('.$this->fileHeader->compressed.' bytes)' ); + } + + + // Decide filetype -- Check for directories + $this->fileHeader->type = 'file'; + if( strrpos($this->fileHeader->file, '/') == strlen($this->fileHeader->file) - 1 ) $this->fileHeader->type = 'dir'; + // Decide filetype -- Check for symbolic links + if( ($headerData['ver1'] == 10) && ($headerData['ver2'] == 3) )$this->fileHeader->type = 'link'; + + switch( $headerData['compmethod'] ) + { + case 0: + $this->fileHeader->compression = 'none'; + break; + case 8: + $this->fileHeader->compression = 'gzip'; + break; + } + + // Find hard-coded banned files + if( (basename($this->fileHeader->file) == ".") || (basename($this->fileHeader->file) == "..") ) + { + $isBannedFile = true; + } + + // Also try to find banned files passed in class configuration + if((count($this->skipFiles) > 0) && (!$isRenamed)) + { + if(in_array($this->fileHeader->file, $this->skipFiles)) + { + $isBannedFile = true; + } + } + + // If we have a banned file, let's skip it + if($isBannedFile) + { + // Advance the file pointer, skipping exactly the size of the compressed data + $seekleft = $this->fileHeader->compressed; + while($seekleft > 0) + { + // Ensure that we can seek past archive part boundaries + $curSize = @filesize($this->archiveList[$this->currentPartNumber]); + $curPos = @ftell($this->fp); + $canSeek = $curSize - $curPos; + if($canSeek > $seekleft) $canSeek = $seekleft; + @fseek( $this->fp, $canSeek, SEEK_CUR ); + $seekleft -= $canSeek; + if($seekleft) $this->nextFile(); + } + + $this->currentPartOffset = @ftell($this->fp); + $this->runState = AK_STATE_DONE; + return true; + } + + // Last chance to prepend a path to the filename + if(!empty($this->addPath) && !$isDirRenamed) + { + $this->fileHeader->file = $this->addPath.$this->fileHeader->file; + } + + // Get the translated path name + if($this->fileHeader->type == 'file') + { + $this->fileHeader->realFile = $this->postProcEngine->processFilename( $this->fileHeader->file ); + } + elseif($this->fileHeader->type == 'dir') + { + $this->fileHeader->timestamp = 0; + + $dir = $this->fileHeader->file; + + $this->postProcEngine->createDirRecursive( $this->fileHeader->file, 0755 ); + $this->postProcEngine->processFilename(null); + } + else + { + // Symlink; do not post-process + $this->fileHeader->timestamp = 0; + $this->postProcEngine->processFilename(null); + } + + $this->createDirectory(); + + // Header is read + $this->runState = AK_STATE_HEADER; + + return true; + } + +} + +/** + * Timer class + */ +class AKCoreTimer extends AKAbstractObject +{ + /** @var int Maximum execution time allowance per step */ + private $max_exec_time = null; + + /** @var int Timestamp of execution start */ + private $start_time = null; + + /** + * Public constructor, creates the timer object and calculates the execution time limits + * @return AECoreTimer + */ + public function __construct() + { + parent::__construct(); + + // Initialize start time + $this->start_time = $this->microtime_float(); + + // Get configured max time per step and bias + $config_max_exec_time = AKFactory::get('kickstart.tuning.max_exec_time', 14); + $bias = AKFactory::get('kickstart.tuning.run_time_bias', 75)/100; + + // Get PHP's maximum execution time (our upper limit) + if(@function_exists('ini_get')) + { + $php_max_exec_time = @ini_get("maximum_execution_time"); + if ( (!is_numeric($php_max_exec_time)) || ($php_max_exec_time == 0) ) { + // If we have no time limit, set a hard limit of about 10 seconds + // (safe for Apache and IIS timeouts, verbose enough for users) + $php_max_exec_time = 14; + } + } + else + { + // If ini_get is not available, use a rough default + $php_max_exec_time = 14; + } + + // Apply an arbitrary correction to counter CMS load time + $php_max_exec_time--; + + // Apply bias + $php_max_exec_time = $php_max_exec_time * $bias; + $config_max_exec_time = $config_max_exec_time * $bias; + + // Use the most appropriate time limit value + if( $config_max_exec_time > $php_max_exec_time ) + { + $this->max_exec_time = $php_max_exec_time; + } + else + { + $this->max_exec_time = $config_max_exec_time; + } + } + + /** + * Wake-up function to reset internal timer when we get unserialized + */ + public function __wakeup() + { + // Re-initialize start time on wake-up + $this->start_time = $this->microtime_float(); + } + + /** + * Gets the number of seconds left, before we hit the "must break" threshold + * @return float + */ + public function getTimeLeft() + { + return $this->max_exec_time - $this->getRunningTime(); + } + + /** + * Gets the time elapsed since object creation/unserialization, effectively how + * long Akeeba Engine has been processing data + * @return float + */ + public function getRunningTime() + { + return $this->microtime_float() - $this->start_time; + } + + /** + * Returns the current timestampt in decimal seconds + */ + private function microtime_float() + { + list($usec, $sec) = explode(" ", microtime()); + return ((float)$usec + (float)$sec); + } + + /** + * Enforce the minimum execution time + */ + public function enforce_min_exec_time() + { + // Try to get a sane value for PHP's maximum_execution_time INI parameter + if(@function_exists('ini_get')) + { + $php_max_exec = @ini_get("maximum_execution_time"); + } + else + { + $php_max_exec = 10; + } + if ( ($php_max_exec == "") || ($php_max_exec == 0) ) { + $php_max_exec = 10; + } + // Decrease $php_max_exec time by 500 msec we need (approx.) to tear down + // the application, as well as another 500msec added for rounding + // error purposes. Also make sure this is never gonna be less than 0. + $php_max_exec = max($php_max_exec * 1000 - 1000, 0); + + // Get the "minimum execution time per step" Akeeba Backup configuration variable + $minexectime = AKFactory::get('kickstart.tuning.min_exec_time',0); + if(!is_numeric($minexectime)) $minexectime = 0; + + // Make sure we are not over PHP's time limit! + if($minexectime > $php_max_exec) $minexectime = $php_max_exec; + + // Get current running time + $elapsed_time = $this->getRunningTime() * 1000; + + // Only run a sleep delay if we haven't reached the minexectime execution time + if( ($minexectime > $elapsed_time) && ($elapsed_time > 0) ) + { + $sleep_msec = $minexectime - $elapsed_time; + if(function_exists('usleep')) + { + usleep(1000 * $sleep_msec); + } + elseif(function_exists('time_nanosleep')) + { + $sleep_sec = floor($sleep_msec / 1000); + $sleep_nsec = 1000000 * ($sleep_msec - ($sleep_sec * 1000)); + time_nanosleep($sleep_sec, $sleep_nsec); + } + elseif(function_exists('time_sleep_until')) + { + $until_timestamp = time() + $sleep_msec / 1000; + time_sleep_until($until_timestamp); + } + elseif(function_exists('sleep')) + { + $sleep_sec = ceil($sleep_msec/1000); + sleep( $sleep_sec ); + } + } + elseif( $elapsed_time > 0 ) + { + // No sleep required, even if user configured us to be able to do so. + } + } + + /** + * Reset the timer. It should only be used in CLI mode! + */ + public function resetTime() + { + $this->start_time = $this->microtime_float(); + } +} + +/** + * JPS archive extraction class + */ +class AKUnarchiverJPS extends AKUnarchiverJPA +{ + private $archiveHeaderData = array(); + + private $password = ''; + + public function __construct() + { + parent::__construct(); + + $this->password = AKFactory::get('kickstart.jps.password',''); + } + + protected function readArchiveHeader() + { + // Initialize header data array + $this->archiveHeaderData = new stdClass(); + + // Open the first part + $this->nextFile(); + + // Fail for unreadable files + if( $this->fp === false ) return false; + + // Read the signature + $sig = fread( $this->fp, 3 ); + + if ($sig != 'JPS') + { + // Not a JPA file + $this->setError( AKText::_('ERR_NOT_A_JPS_FILE') ); + return false; + } + + // Read and parse the known portion of header data (5 bytes) + $bin_data = fread($this->fp, 5); + $header_data = unpack('Cmajor/Cminor/cspanned/vextra', $bin_data); + + // Load any remaining header data (forward compatibility) + $rest_length = $header_data['extra']; + if( $rest_length > 0 ) + $junk = fread($this->fp, $rest_length); + else + $junk = ''; + + // Temporary array with all the data we read + $temp = array( + 'signature' => $sig, + 'major' => $header_data['major'], + 'minor' => $header_data['minor'], + 'spanned' => $header_data['spanned'] + ); + // Array-to-object conversion + foreach($temp as $key => $value) + { + $this->archiveHeaderData->{$key} = $value; + } + + $this->currentPartOffset = @ftell($this->fp); + + $this->dataReadLength = 0; + + return true; + } + + /** + * Concrete classes must use this method to read the file header + * @return bool True if reading the file was successful, false if an error occured or we reached end of archive + */ + protected function readFileHeader() + { + // If the current part is over, proceed to the next part please + if( $this->isEOF(true) ) { + $this->nextFile(); + } + + // Get and decode Entity Description Block + $signature = fread($this->fp, 3); + + // Check for end-of-archive siganture + if($signature == 'JPE') + { + $this->setState('postrun'); + return true; + } + + $this->fileHeader = new stdClass(); + $this->fileHeader->timestamp = 0; + + // Check signature + if( $signature != 'JPF' ) + { + if($this->isEOF(true)) + { + // This file is finished; make sure it's the last one + $this->nextFile(); + if(!$this->isEOF(false)) + { + $this->setError(AKText::sprintf('INVALID_FILE_HEADER', $this->currentPartNumber, $this->currentPartOffset)); + return false; + } + // We're just finished + return false; + } + else + { + fseek($this->fp, -6, SEEK_CUR); + $signature = fread($this->fp, 3); + if($signature == 'JPE') + { + return false; + } + + $this->setError(AKText::sprintf('INVALID_FILE_HEADER', $this->currentPartNumber, $this->currentPartOffset)); + return false; + } + } + // This a JPA Entity Block. Process the header. + + $isBannedFile = false; + + // Read and decrypt the header + $edbhData = fread($this->fp, 4); + $edbh = unpack('vencsize/vdecsize', $edbhData); + $bin_data = fread($this->fp, $edbh['encsize']); + + // Decrypt and truncate + $bin_data = AKEncryptionAES::AESDecryptCBC($bin_data, $this->password, 128); + $bin_data = substr($bin_data,0,$edbh['decsize']); + + // Read length of EDB and of the Entity Path Data + $length_array = unpack('vpathsize', substr($bin_data,0,2) ); + // Read the path data + $file = substr($bin_data,2,$length_array['pathsize']); + + // Handle file renaming + $isRenamed = false; + if(is_array($this->renameFiles) && (count($this->renameFiles) > 0) ) + { + if(array_key_exists($file, $this->renameFiles)) + { + $file = $this->renameFiles[$file]; + $isRenamed = true; + } + } + + // Handle directory renaming + $isDirRenamed = false; + if(is_array($this->renameDirs) && (count($this->renameDirs) > 0)) { + if(array_key_exists(dirname($file), $this->renameDirs)) { + $file = rtrim($this->renameDirs[dirname($file)],'/').'/'.basename($file); + $isRenamed = true; + $isDirRenamed = true; + } + } + + // Read and parse the known data portion + $bin_data = substr($bin_data, 2 + $length_array['pathsize']); + $header_data = unpack('Ctype/Ccompression/Vuncompsize/Vperms/Vfilectime', $bin_data); + + $this->fileHeader->timestamp = $header_data['filectime']; + $compressionType = $header_data['compression']; + + // Populate the return array + $this->fileHeader->file = $file; + $this->fileHeader->uncompressed = $header_data['uncompsize']; + switch($header_data['type']) + { + case 0: + $this->fileHeader->type = 'dir'; + break; + + case 1: + $this->fileHeader->type = 'file'; + break; + + case 2: + $this->fileHeader->type = 'link'; + break; + } + switch( $compressionType ) + { + case 0: + $this->fileHeader->compression = 'none'; + break; + case 1: + $this->fileHeader->compression = 'gzip'; + break; + case 2: + $this->fileHeader->compression = 'bzip2'; + break; + } + $this->fileHeader->permissions = $header_data['perms']; + + // Find hard-coded banned files + if( (basename($this->fileHeader->file) == ".") || (basename($this->fileHeader->file) == "..") ) + { + $isBannedFile = true; + } + + // Also try to find banned files passed in class configuration + if((count($this->skipFiles) > 0) && (!$isRenamed) ) + { + if(in_array($this->fileHeader->file, $this->skipFiles)) + { + $isBannedFile = true; + } + } + + // If we have a banned file, let's skip it + if($isBannedFile) + { + $done = false; + while(!$done) + { + // Read the Data Chunk Block header + $binMiniHead = fread($this->fp, 8); + if( in_array( substr($binMiniHead,0,3), array('JPF','JPE') ) ) + { + // Not a Data Chunk Block header, I am done skipping the file + @fseek($this->fp,-8,SEEK_CUR); // Roll back the file pointer + $done = true; // Mark as done + continue; // Exit loop + } + else + { + // Skip forward by the amount of compressed data + $miniHead = unpack('Vencsize/Vdecsize'); + @fseek($this->fp, $miniHead['encsize'], SEEK_CUR); + } + } + + $this->currentPartOffset = @ftell($this->fp); + $this->runState = AK_STATE_DONE; + return true; + } + + // Last chance to prepend a path to the filename + if(!empty($this->addPath) && !$isDirRenamed) + { + $this->fileHeader->file = $this->addPath.$this->fileHeader->file; + } + + // Get the translated path name + $restorePerms = AKFactory::get('kickstart.setup.restoreperms', false); + if($this->fileHeader->type == 'file') + { + // Regular file; ask the postproc engine to process its filename + if($restorePerms) + { + $this->fileHeader->realFile = $this->postProcEngine->processFilename( $this->fileHeader->file, $this->fileHeader->permissions ); + } + else + { + $this->fileHeader->realFile = $this->postProcEngine->processFilename( $this->fileHeader->file ); + } + } + elseif($this->fileHeader->type == 'dir') + { + $dir = $this->fileHeader->file; + $this->fileHeader->realFile = $dir; + + // Directory; just create it + if($restorePerms) + { + $this->postProcEngine->createDirRecursive( $this->fileHeader->file, $this->fileHeader->permissions ); + } + else + { + $this->postProcEngine->createDirRecursive( $this->fileHeader->file, 0755 ); + } + $this->postProcEngine->processFilename(null); + } + else + { + // Symlink; do not post-process + $this->postProcEngine->processFilename(null); + } + + $this->createDirectory(); + + // Header is read + $this->runState = AK_STATE_HEADER; + + $this->dataReadLength = 0; + + return true; + } + + /** + * Concrete classes must use this method to process file data. It must set $runState to AK_STATE_DATAREAD when + * it's finished processing the file data. + * @return bool True if processing the file data was successful, false if an error occured + */ + protected function processFileData() + { + switch( $this->fileHeader->type ) + { + case 'dir': + return $this->processTypeDir(); + break; + + case 'link': + return $this->processTypeLink(); + break; + + case 'file': + switch($this->fileHeader->compression) + { + case 'none': + return $this->processTypeFileUncompressed(); + break; + + case 'gzip': + case 'bzip2': + return $this->processTypeFileCompressedSimple(); + break; + + } + break; + } + } + + private function processTypeFileUncompressed() + { + // Uncompressed files are being processed in small chunks, to avoid timeouts + if( ($this->dataReadLength == 0) && !AKFactory::get('kickstart.setup.dryrun','0') ) + { + // Before processing file data, ensure permissions are adequate + $this->setCorrectPermissions( $this->fileHeader->file ); + } + + // Open the output file + if( !AKFactory::get('kickstart.setup.dryrun','0') ) + { + $ignore = AKFactory::get('kickstart.setup.ignoreerrors', false); + if ($this->dataReadLength == 0) { + $outfp = @fopen( $this->fileHeader->realFile, 'wb' ); + } else { + $outfp = @fopen( $this->fileHeader->realFile, 'ab' ); + } + + // Can we write to the file? + if( ($outfp === false) && (!$ignore) ) { + // An error occured + $this->setError( AKText::sprintf('COULDNT_WRITE_FILE', $this->fileHeader->realFile) ); + return false; + } + } + + // Does the file have any data, at all? + if( $this->fileHeader->uncompressed == 0 ) + { + // No file data! + if( !AKFactory::get('kickstart.setup.dryrun','0') && is_resource($outfp) ) @fclose($outfp); + $this->runState = AK_STATE_DATAREAD; + return true; + } + else + { + $this->setError('An uncompressed file was detected; this is not supported by this archive extraction utility'); + return false; + } + + return true; + } + + private function processTypeFileCompressedSimple() + { + $timer = AKFactory::getTimer(); + + // Files are being processed in small chunks, to avoid timeouts + if( ($this->dataReadLength == 0) && !AKFactory::get('kickstart.setup.dryrun','0') ) + { + // Before processing file data, ensure permissions are adequate + $this->setCorrectPermissions( $this->fileHeader->file ); + } + + // Open the output file + if( !AKFactory::get('kickstart.setup.dryrun','0') ) + { + // Open the output file + $outfp = @fopen( $this->fileHeader->realFile, 'wb' ); + + // Can we write to the file? + $ignore = AKFactory::get('kickstart.setup.ignoreerrors', false); + if( ($outfp === false) && (!$ignore) ) { + // An error occured + $this->setError( AKText::sprintf('COULDNT_WRITE_FILE', $this->fileHeader->realFile) ); + return false; + } + } + + // Does the file have any data, at all? + if( $this->fileHeader->uncompressed == 0 ) + { + // No file data! + if( !AKFactory::get('kickstart.setup.dryrun','0') ) + if(is_resource($outfp)) @fclose($outfp); + $this->runState = AK_STATE_DATAREAD; + return true; + } + + $leftBytes = $this->fileHeader->uncompressed - $this->dataReadLength; + + // Loop while there's data to write and enough time to do it + while( ($leftBytes > 0) && ($timer->getTimeLeft() > 0) ) + { + // Read the mini header + $binMiniHeader = fread($this->fp, 8); + $reallyReadBytes = akstringlen($binMiniHeader); + if($reallyReadBytes < 8) + { + // We read less than requested! Why? Did we hit local EOF? + if( $this->isEOF(true) && !$this->isEOF(false) ) + { + // Yeap. Let's go to the next file + $this->nextFile(); + // Retry reading the header + $binMiniHeader = fread($this->fp, 8); + $reallyReadBytes = akstringlen($binMiniHeader); + // Still not enough data? If so, the archive is corrupt or missing parts. + if($reallyReadBytes < 8) { + $this->setError( AKText::_('ERR_CORRUPT_ARCHIVE') ); + return false; + } + } + else + { + // Nope. The archive is corrupt + $this->setError( AKText::_('ERR_CORRUPT_ARCHIVE') ); + return false; + } + } + + // Read the encrypted data + $miniHeader = unpack('Vencsize/Vdecsize', $binMiniHeader); + $toReadBytes = $miniHeader['encsize']; + $data = $this->fread( $this->fp, $toReadBytes ); + $reallyReadBytes = akstringlen($data); + if($reallyReadBytes < $toReadBytes) + { + // We read less than requested! Why? Did we hit local EOF? + if( $this->isEOF(true) && !$this->isEOF(false) ) + { + // Yeap. Let's go to the next file + $this->nextFile(); + // Read the rest of the data + $toReadBytes -= $reallyReadBytes; + $restData = $this->fread( $this->fp, $toReadBytes ); + $reallyReadBytes = akstringlen($restData); + if($reallyReadBytes < $toReadBytes) { + $this->setError( AKText::_('ERR_CORRUPT_ARCHIVE') ); + return false; + } + if(akstringlen($data) == 0) { + $data = $restData; + } else { + $data .= $restData; + } + } + else + { + // Nope. The archive is corrupt + $this->setError( AKText::_('ERR_CORRUPT_ARCHIVE') ); + return false; + } + } + + // Decrypt the data + $data = AKEncryptionAES::AESDecryptCBC($data, $this->password, 128); + + // Is the length of the decrypted data less than expected? + $data_length = akstringlen($data); + if($data_length < $miniHeader['decsize']) { + $this->setError(AKText::_('ERR_INVALID_JPS_PASSWORD')); + return false; + } + + // Trim the data + $data = substr($data,0,$miniHeader['decsize']); + + // Decompress + $data = gzinflate($data); + $unc_len = akstringlen($data); + + // Write the decrypted data + if( !AKFactory::get('kickstart.setup.dryrun','0') ) + if(is_resource($outfp)) @fwrite( $outfp, $data, akstringlen($data) ); + + // Update the read length + $this->dataReadLength += $unc_len; + $leftBytes = $this->fileHeader->uncompressed - $this->dataReadLength; + } + + // Close the file pointer + if( !AKFactory::get('kickstart.setup.dryrun','0') ) + if(is_resource($outfp)) @fclose($outfp); + + // Was this a pre-timeout bail out? + if( $leftBytes > 0 ) + { + $this->runState = AK_STATE_DATA; + } + else + { + // Oh! We just finished! + $this->runState = AK_STATE_DATAREAD; + $this->dataReadLength = 0; + } + } + + /** + * Process the file data of a link entry + * @return bool + */ + private function processTypeLink() + { + + // Does the file have any data, at all? + if( $this->fileHeader->uncompressed == 0 ) + { + // No file data! + $this->runState = AK_STATE_DATAREAD; + return true; + } + + // Read the mini header + $binMiniHeader = fread($this->fp, 8); + $reallyReadBytes = akstringlen($binMiniHeader); + if($reallyReadBytes < 8) + { + // We read less than requested! Why? Did we hit local EOF? + if( $this->isEOF(true) && !$this->isEOF(false) ) + { + // Yeap. Let's go to the next file + $this->nextFile(); + // Retry reading the header + $binMiniHeader = fread($this->fp, 8); + $reallyReadBytes = akstringlen($binMiniHeader); + // Still not enough data? If so, the archive is corrupt or missing parts. + if($reallyReadBytes < 8) { + $this->setError( AKText::_('ERR_CORRUPT_ARCHIVE') ); + return false; + } + } + else + { + // Nope. The archive is corrupt + $this->setError( AKText::_('ERR_CORRUPT_ARCHIVE') ); + return false; + } + } + + // Read the encrypted data + $miniHeader = unpack('Vencsize/Vdecsize', $binMiniHeader); + $toReadBytes = $miniHeader['encsize']; + $data = $this->fread( $this->fp, $toReadBytes ); + $reallyReadBytes = akstringlen($data); + if($reallyReadBytes < $toReadBytes) + { + // We read less than requested! Why? Did we hit local EOF? + if( $this->isEOF(true) && !$this->isEOF(false) ) + { + // Yeap. Let's go to the next file + $this->nextFile(); + // Read the rest of the data + $toReadBytes -= $reallyReadBytes; + $restData = $this->fread( $this->fp, $toReadBytes ); + $reallyReadBytes = akstringlen($data); + if($reallyReadBytes < $toReadBytes) { + $this->setError( AKText::_('ERR_CORRUPT_ARCHIVE') ); + return false; + } + $data .= $restData; + } + else + { + // Nope. The archive is corrupt + $this->setError( AKText::_('ERR_CORRUPT_ARCHIVE') ); + return false; + } + } + + // Decrypt the data + $data = AKEncryptionAES::AESDecryptCBC($data, $this->password, 128); + + // Is the length of the decrypted data less than expected? + $data_length = akstringlen($data); + if($data_length < $miniHeader['decsize']) { + $this->setError(AKText::_('ERR_INVALID_JPS_PASSWORD')); + return false; + } + + // Trim the data + $data = substr($data,0,$miniHeader['decsize']); + + // Try to remove an existing file or directory by the same name + if(file_exists($this->fileHeader->realFile)) { @unlink($this->fileHeader->realFile); @rmdir($this->fileHeader->realFile); } + // Remove any trailing slash + if(substr($this->fileHeader->realFile, -1) == '/') $this->fileHeader->realFile = substr($this->fileHeader->realFile, 0, -1); + // Create the symlink - only possible within PHP context. There's no support built in the FTP protocol, so no postproc use is possible here :( + if( !AKFactory::get('kickstart.setup.dryrun','0') ) + @symlink($data, $this->fileHeader->realFile); + + $this->runState = AK_STATE_DATAREAD; + + return true; // No matter if the link was created! + } + + /** + * Process the file data of a directory entry + * @return bool + */ + private function processTypeDir() + { + // Directory entries in the JPA do not have file data, therefore we're done processing the entry + $this->runState = AK_STATE_DATAREAD; + return true; + } + + /** + * Creates the directory this file points to + */ + protected function createDirectory() + { + if( AKFactory::get('kickstart.setup.dryrun','0') ) return true; + + // Do we need to create a directory? + $lastSlash = strrpos($this->fileHeader->realFile, '/'); + $dirName = substr( $this->fileHeader->realFile, 0, $lastSlash); + $perms = $this->flagRestorePermissions ? $retArray['permissions'] : 0755; + $ignore = AKFactory::get('kickstart.setup.ignoreerrors', false); + if( ($this->postProcEngine->createDirRecursive($dirName, $perms) == false) && (!$ignore) ) { + $this->setError( AKText::sprintf('COULDNT_CREATE_DIR', $dirName) ); + return false; + } + else + { + return true; + } + } +} + +/** + * A filesystem scanner which uses opendir() + */ +class AKUtilsLister extends AKAbstractObject +{ + public function &getFiles($folder, $pattern = '*') + { + // Initialize variables + $arr = array(); + $false = false; + + if(!is_dir($folder)) return $false; + + $handle = @opendir($folder); + // If directory is not accessible, just return FALSE + if ($handle === FALSE) { + $this->setWarning( 'Unreadable directory '.$folder); + return $false; + } + + while (($file = @readdir($handle)) !== false) + { + if( !fnmatch($pattern, $file) ) continue; + + if (($file != '.') && ($file != '..')) + { + $ds = ($folder == '') || ($folder == '/') || (@substr($folder, -1) == '/') || (@substr($folder, -1) == DIRECTORY_SEPARATOR) ? '' : DIRECTORY_SEPARATOR; + $dir = $folder . $ds . $file; + $isDir = is_dir($dir); + if (!$isDir) { + $arr[] = $dir; + } + } + } + @closedir($handle); + + return $arr; + } + + public function &getFolders($folder, $pattern = '*') + { + // Initialize variables + $arr = array(); + $false = false; + + if(!is_dir($folder)) return $false; + + $handle = @opendir($folder); + // If directory is not accessible, just return FALSE + if ($handle === FALSE) { + $this->setWarning( 'Unreadable directory '.$folder); + return $false; + } + + while (($file = @readdir($handle)) !== false) + { + if( !fnmatch($pattern, $file) ) continue; + + if (($file != '.') && ($file != '..')) + { + $ds = ($folder == '') || ($folder == '/') || (@substr($folder, -1) == '/') || (@substr($folder, -1) == DIRECTORY_SEPARATOR) ? '' : DIRECTORY_SEPARATOR; + $dir = $folder . $ds . $file; + $isDir = is_dir($dir); + if ($isDir) { + $arr[] = $dir; + } + } + } + @closedir($handle); + + return $arr; + } +} + +/** + * A simple INI-based i18n engine + */ + +class AKText extends AKAbstractObject +{ + /** + * The default (en_GB) translation used when no other translation is available + * @var array + */ + private $default_translation = array( + 'AUTOMODEON' => 'Auto-mode enabled', + 'ERR_NOT_A_JPA_FILE' => 'The file is not a JPA archive', + 'ERR_CORRUPT_ARCHIVE' => 'The archive file is corrupt, truncated or archive parts are missing', + 'ERR_INVALID_LOGIN' => 'Invalid login', + 'COULDNT_CREATE_DIR' => 'Could not create %s folder', + 'COULDNT_WRITE_FILE' => 'Could not open %s for writing.', + 'WRONG_FTP_HOST' => 'Wrong FTP host or port', + 'WRONG_FTP_USER' => 'Wrong FTP username or password', + 'WRONG_FTP_PATH1' => 'Wrong FTP initial directory - the directory doesn\'t exist', + 'FTP_CANT_CREATE_DIR' => 'Could not create directory %s', + 'FTP_TEMPDIR_NOT_WRITABLE' => 'Could not find or create a writable temporary directory', + 'FTP_COULDNT_UPLOAD' => 'Could not upload %s', + 'THINGS_HEADER' => 'Things you should know about Akeeba Kickstart', + 'THINGS_01' => 'Kickstart is not an installer. It is an archive extraction tool. The actual installer was put inside the archive file at backup time.', + 'THINGS_02' => 'Kickstart is not the only way to extract the backup archive. You can use Akeeba eXtract Wizard and upload the extracted files using FTP instead.', + 'THINGS_03' => 'Kickstart is bound by your server\'s configuration. As such, it may not work at all.', + 'THINGS_04' => 'You should download and upload your archive files using FTP in Binary transfer mode. Any other method could lead to a corrupt backup archive and restoration failure.', + 'THINGS_05' => 'Post-restoration site load errors are usually caused by .htaccess or php.ini directives. You should understand that blank pages, 404 and 500 errors can usually be worked around by editing the aforementioned files. It is not our job to mess with your configuration files, because this could be dangerous for your site.', + 'THINGS_06' => 'Kickstart overwrites files without a warning. If you are not sure that you are OK with that do not continue.', + 'THINGS_07' => 'Trying to restore to the temporary URL of a cPanel host (e.g. http://1.2.3.4/~username) will lead to restoration failure and your site will appear to be not working. This is normal and it\'s just how your server and CMS software work.', + 'THINGS_08' => 'You are supposed to read the documentation before using this software. Most issues can be avoided, or easily worked around, by understanding how this software works.', + 'THINGS_09' => 'This text does not imply that there is a problem detected. It is standard text displayed every time you launch Kickstart.', + 'CLOSE_LIGHTBOX' => 'Click here or press ESC to close this message', + 'SELECT_ARCHIVE' => 'Select a backup archive', + 'ARCHIVE_FILE' => 'Archive file:', + 'SELECT_EXTRACTION' => 'Select an extraction method', + 'WRITE_TO_FILES' => 'Write to files:', + 'WRITE_DIRECTLY' => 'Directly', + 'WRITE_FTP' => 'Use FTP', + 'FTP_HOST' => 'FTP host name:', + 'FTP_PORT' => 'FTP port:', + 'FTP_FTPS' => 'Use FTP over SSL (FTPS)', + 'FTP_PASSIVE' => 'Use FTP Passive Mode', + 'FTP_USER' => 'FTP user name:', + 'FTP_PASS' => 'FTP password:', + 'FTP_DIR' => 'FTP directory:', + 'FTP_TEMPDIR' => 'Temporary directory:', + 'FTP_CONNECTION_OK' => 'FTP Connection Established', + 'FTP_CONNECTION_FAILURE' => 'The FTP Connection Failed', + 'FTP_TEMPDIR_WRITABLE' => 'The temporary directory is writable.', + 'FTP_TEMPDIR_UNWRITABLE' => 'The temporary directory is not writable. Please check the permissions.', + 'BTN_CHECK' => 'Check', + 'BTN_RESET' => 'Reset', + 'BTN_TESTFTPCON' => 'Test FTP connection', + 'BTN_GOTOSTART' => 'Start over', + 'FINE_TUNE' => 'Fine tune', + 'MIN_EXEC_TIME' => 'Minimum execution time:', + 'MAX_EXEC_TIME' => 'Maximum execution time:', + 'SECONDS_PER_STEP' => 'seconds per step', + 'EXTRACT_FILES' => 'Extract files', + 'BTN_START' => 'Start', + 'EXTRACTING' => 'Extracting', + 'DO_NOT_CLOSE_EXTRACT' => 'Do not close this window while the extraction is in progress', + 'RESTACLEANUP' => 'Restoration and Clean Up', + 'BTN_RUNINSTALLER' => 'Run the Installer', + 'BTN_CLEANUP' => 'Clean Up', + 'BTN_SITEFE' => 'Visit your site\'s front-end', + 'BTN_SITEBE' => 'Visit your site\'s back-end', + 'WARNINGS' => 'Extraction Warnings', + 'ERROR_OCCURED' => 'An error occured', + 'STEALTH_MODE' => 'Stealth mode', + 'STEALTH_URL' => 'HTML file to show to web visitors', + 'ERR_NOT_A_JPS_FILE' => 'The file is not a JPA archive', + 'ERR_INVALID_JPS_PASSWORD' => 'The password you gave is wrong or the archive is corrupt', + 'JPS_PASSWORD' => 'Archive Password (for JPS files)', + 'INVALID_FILE_HEADER' => 'Invalid header in archive file, part %s, offset %s', + 'NEEDSOMEHELPKS' => 'Want some help to use this tool? Read this first:', + 'QUICKSTART' => 'Quick Start Guide', + 'CANTGETITTOWORK' => 'Can\'t get it to work? Click me!', + 'NOARCHIVESCLICKHERE' => 'No archives detected. Click here for troubleshooting instructions.', + 'POSTRESTORATIONTROUBLESHOOTING' => 'Something not working after the restoration? Click here for troubleshooting instructions.', + 'UPDATE_HEADER' => 'An updated version of Akeeba Kickstart (unknown) is available!', + 'UPDATE_NOTICE' => 'You are advised to always use the latest version of Akeeba Kickstart available. Older versions may be subject to bugs and will not be supported.', + 'UPDATE_DLNOW' => 'Download now', + 'UPDATE_MOREINFO' => 'More information' + ); + + /** + * The array holding the translation keys + * @var array + */ + private $strings; + + /** + * The currently detected language (ISO code) + * @var string + */ + private $language; + + /* + * Initializes the translation engine + * @return AKText + */ + public function __construct() + { + // Start with the default translation + $this->strings = $this->default_translation; + // Try loading the translation file in English, if it exists + $this->loadTranslation('en-GB'); + // Try loading the translation file in the browser's preferred language, if it exists + $this->getBrowserLanguage(); + if(!is_null($this->language)) + { + $this->loadTranslation(); + } + } + + /** + * Singleton pattern for Language + * @return Language The global Language instance + */ + public static function &getInstance() + { + static $instance; + + if(!is_object($instance)) + { + $instance = new AKText(); + } + + return $instance; + } + + public static function _($string) + { + $text = self::getInstance(); + + $key = strtoupper($string); + $key = substr($key, 0, 1) == '_' ? substr($key, 1) : $key; + + if (isset ($text->strings[$key])) + { + $string = $text->strings[$key]; + } + else + { + if (defined($string)) + { + $string = constant($string); + } + } + + return $string; + } + + public static function sprintf($key) + { + $text = self::getInstance(); + $args = func_get_args(); + if (count($args) > 0) { + $args[0] = $text->_($args[0]); + return @call_user_func_array('sprintf', $args); + } + return ''; + } + + public function dumpLanguage() + { + $out = ''; + foreach($this->strings as $key => $value) + { + $out .= "$key=$value\n"; + } + return $out; + } + + public function asJavascript() + { + $out = ''; + foreach($this->strings as $key => $value) + { + $key = addcslashes($key, '\\\'"'); + $value = addcslashes($value, '\\\'"'); + if(!empty($out)) $out .= ",\n"; + $out .= "'$key':\t'$value'"; + } + return $out; + } + + public function resetTranslation() + { + $this->strings = $this->default_translation; + } + + public function getBrowserLanguage() + { + // Detection code from Full Operating system language detection, by Harald Hope + // Retrieved from http://techpatterns.com/downloads/php_language_detection.php + $user_languages = array(); + //check to see if language is set + if ( isset( $_SERVER["HTTP_ACCEPT_LANGUAGE"] ) ) + { + $languages = strtolower( $_SERVER["HTTP_ACCEPT_LANGUAGE"] ); + // $languages = ' fr-ch;q=0.3, da, en-us;q=0.8, en;q=0.5, fr;q=0.3'; + // need to remove spaces from strings to avoid error + $languages = str_replace( ' ', '', $languages ); + $languages = explode( ",", $languages ); + + foreach ( $languages as $language_list ) + { + // pull out the language, place languages into array of full and primary + // string structure: + $temp_array = array(); + // slice out the part before ; on first step, the part before - on second, place into array + $temp_array[0] = substr( $language_list, 0, strcspn( $language_list, ';' ) );//full language + $temp_array[1] = substr( $language_list, 0, 2 );// cut out primary language + if( (strlen($temp_array[0]) == 5) && ( (substr($temp_array[0],2,1) == '-') || (substr($temp_array[0],2,1) == '_') ) ) + { + $langLocation = strtoupper(substr($temp_array[0],3,2)); + $temp_array[0] = $temp_array[1].'-'.$langLocation; + } + //place this array into main $user_languages language array + $user_languages[] = $temp_array; + } + } + else// if no languages found + { + $user_languages[0] = array( '','' ); //return blank array. + } + + $this->language = null; + $basename=basename(__FILE__, '.php') . '.ini'; + + // Try to match main language part of the filename, irrespective of the location, e.g. de_DE will do if de_CH doesn't exist. + $fs = new AKUtilsLister(); + $iniFiles = $fs->getFiles( dirname(__FILE__), '*.'.$basename ); + if(empty($iniFiles) && ($basename != 'kickstart.ini')) { + $basename = 'kickstart.ini'; + $iniFiles = $fs->getFiles( dirname(__FILE__), '*.'.$basename ); + } + if (is_array($iniFiles)) { + foreach($user_languages as $languageStruct) + { + if(is_null($this->language)) + { + // Get files matching the main lang part + $iniFiles = $fs->getFiles( dirname(__FILE__), $languageStruct[1].'-??.'.$basename ); + if (count($iniFiles) > 0) { + $filename = $iniFiles[0]; + $filename = substr($filename, strlen(dirname(__FILE__))+1); + $this->language = substr($filename, 0, 5); + } else { + $this->language = null; + } + } + } + } + + if(is_null($this->language)) { + // Try to find a full language match + foreach($user_languages as $languageStruct) + { + if (@file_exists($languageStruct[0].'.'.$basename) && is_null($this->language)) { + $this->language = $languageStruct[0]; + } else { + + } + } + } else { + // Do we have an exact match? + foreach($user_languages as $languageStruct) + { + if(substr($this->language,0,strlen($languageStruct[1])) == $languageStruct[1]) { + if(file_exists($languageStruct[0].'.'.$basename)) { + $this->language = $languageStruct[0]; + } + } + } + } + + // Now, scan for full language based on the partial match + + } + + private function loadTranslation( $lang = null ) + { + $dirname = function_exists('getcwd') ? getcwd() : dirname(__FILE__); + $basename=basename(__FILE__, '.php') . '.ini'; + if( empty($lang) ) $lang = $this->language; + + $translationFilename = $dirname.DIRECTORY_SEPARATOR.$lang.'.'.$basename; + if(!@file_exists($translationFilename) && ($basename != 'kickstart.ini')) { + $basename = 'kickstart.ini'; + $translationFilename = $dirname.DIRECTORY_SEPARATOR.$lang.'.'.$basename; + } + if(!@file_exists($translationFilename)) return; + $temp = self::parse_ini_file($translationFilename, false); + + if(!is_array($this->strings)) $this->strings = array(); + if(empty($temp)) { + $this->strings = array_merge($this->default_translation, $this->strings); + } else { + $this->strings = array_merge($this->strings, $temp); + } + } + + /** + * A PHP based INI file parser. + * + * Thanks to asohn ~at~ aircanopy ~dot~ net for posting this handy function on + * the parse_ini_file page on http://gr.php.net/parse_ini_file + * + * @param string $file Filename to process + * @param bool $process_sections True to also process INI sections + * @return array An associative array of sections, keys and values + * @access private + */ + public static function parse_ini_file($file, $process_sections = false, $raw_data = false) + { + $process_sections = ($process_sections !== true) ? false : true; + + if(!$raw_data) + { + $ini = @file($file); + } + else + { + $ini = $file; + } + if (count($ini) == 0) {return array();} + + $sections = array(); + $values = array(); + $result = array(); + $globals = array(); + $i = 0; + if(!empty($ini)) foreach ($ini as $line) { + $line = trim($line); + $line = str_replace("\t", " ", $line); + + // Comments + if (!preg_match('/^[a-zA-Z0-9[]/', $line)) {continue;} + + // Sections + if ($line{0} == '[') { + $tmp = explode(']', $line); + $sections[] = trim(substr($tmp[0], 1)); + $i++; + continue; + } + + // Key-value pair + list($key, $value) = explode('=', $line, 2); + $key = trim($key); + $value = trim($value); + if (strstr($value, ";")) { + $tmp = explode(';', $value); + if (count($tmp) == 2) { + if ((($value{0} != '"') && ($value{0} != "'")) || + preg_match('/^".*"\s*;/', $value) || preg_match('/^".*;[^"]*$/', $value) || + preg_match("/^'.*'\s*;/", $value) || preg_match("/^'.*;[^']*$/", $value) ){ + $value = $tmp[0]; + } + } else { + if ($value{0} == '"') { + $value = preg_replace('/^"(.*)".*/', '$1', $value); + } elseif ($value{0} == "'") { + $value = preg_replace("/^'(.*)'.*/", '$1', $value); + } else { + $value = $tmp[0]; + } + } + } + $value = trim($value); + $value = trim($value, "'\""); + + if ($i == 0) { + if (substr($line, -1, 2) == '[]') { + $globals[$key][] = $value; + } else { + $globals[$key] = $value; + } + } else { + if (substr($line, -1, 2) == '[]') { + $values[$i-1][$key][] = $value; + } else { + $values[$i-1][$key] = $value; + } + } + } + + for($j = 0; $j < $i; $j++) { + if ($process_sections === true) { + $result[$sections[$j]] = $values[$j]; + } else { + $result[] = $values[$j]; + } + } + + return $result + $globals; + } +} + +/** + * The Akeeba Kickstart Factory class + * This class is reponssible for instanciating all Akeeba Kicsktart classes + */ +class AKFactory { + /** @var array A list of instanciated objects */ + private $objectlist = array(); + + /** @var array Simple hash data storage */ + private $varlist = array(); + + /** Private constructor makes sure we can't directly instanciate the class */ + private function __construct() {} + + /** + * Gets a single, internally used instance of the Factory + * @param string $serialized_data [optional] Serialized data to spawn the instance from + * @return AKFactory A reference to the unique Factory object instance + */ + protected static function &getInstance( $serialized_data = null ) { + static $myInstance; + if(!is_object($myInstance) || !is_null($serialized_data)) + if(!is_null($serialized_data)) + { + $myInstance = unserialize($serialized_data); + } + else + { + $myInstance = new self(); + } + return $myInstance; + } + + /** + * Internal function which instanciates a class named $class_name. + * The autoloader + * @param object $class_name + * @return + */ + protected static function &getClassInstance($class_name) { + $self = self::getInstance(); + if(!isset($self->objectlist[$class_name])) + { + $self->objectlist[$class_name] = new $class_name; + } + return $self->objectlist[$class_name]; + } + + // ======================================================================== + // Public factory interface + // ======================================================================== + + /** + * Gets a serialized snapshot of the Factory for safekeeping (hibernate) + * @return string The serialized snapshot of the Factory + */ + public static function serialize() { + $engine = self::getUnarchiver(); + $engine->shutdown(); + $serialized = serialize(self::getInstance()); + + if(function_exists('base64_encode') && function_exists('base64_decode')) + { + $serialized = base64_encode($serialized); + } + return $serialized; + } + + /** + * Regenerates the full Factory state from a serialized snapshot (resume) + * @param string $serialized_data The serialized snapshot to resume from + */ + public static function unserialize($serialized_data) { + if(function_exists('base64_encode') && function_exists('base64_decode')) + { + $serialized_data = base64_decode($serialized_data); + } + self::getInstance($serialized_data); + } + + /** + * Reset the internal factory state, freeing all previously created objects + */ + public static function nuke() + { + $self = self::getInstance(); + foreach($self->objectlist as $key => $object) + { + $self->objectlist[$key] = null; + } + $self->objectlist = array(); + } + + // ======================================================================== + // Public hash data storage interface + // ======================================================================== + + public static function set($key, $value) + { + $self = self::getInstance(); + $self->varlist[$key] = $value; + } + + public static function get($key, $default = null) + { + $self = self::getInstance(); + if( array_key_exists($key, $self->varlist) ) + { + return $self->varlist[$key]; + } + else + { + return $default; + } + } + + // ======================================================================== + // Akeeba Kickstart classes + // ======================================================================== + + /** + * Gets the post processing engine + * @param string $proc_engine + */ + public static function &getPostProc($proc_engine = null) + { + static $class_name; + if( empty($class_name) ) + { + if(empty($proc_engine)) + { + $proc_engine = self::get('kickstart.procengine','direct'); + } + $class_name = 'AKPostproc'.ucfirst($proc_engine); + } + return self::getClassInstance($class_name); + } + + /** + * Gets the unarchiver engine + */ + public static function &getUnarchiver( $configOverride = null ) + { + static $class_name; + + if(!empty($configOverride)) + { + if($configOverride['reset']) { + $class_name = null; + } + } + + if( empty($class_name) ) + { + $filetype = self::get('kickstart.setup.filetype', null); + + if(empty($filetype)) + { + $filename = self::get('kickstart.setup.sourcefile', null); + $basename = basename($filename); + $baseextension = strtoupper(substr($basename,-3)); + switch($baseextension) + { + case 'JPA': + $filetype = 'JPA'; + break; + + case 'JPS': + $filetype = 'JPS'; + break; + + case 'ZIP': + $filetype = 'ZIP'; + break; + + default: + die('Invalid archive type or extension in file '.$filename); + break; + } + } + + $class_name = 'AKUnarchiver'.ucfirst($filetype); + } + + $destdir = self::get('kickstart.setup.destdir', null); + if(empty($destdir)) + { + $destdir = function_exists('getcwd') ? getcwd() : dirname(__FILE__); + } + + $object = self::getClassInstance($class_name); + if( $object->getState() == 'init') + { + // Initialize the object + $config = array( + 'filename' => self::get('kickstart.setup.sourcefile', ''), + 'restore_permissions' => self::get('kickstart.setup.restoreperms', 0), + 'post_proc' => self::get('kickstart.procengine', 'direct'), + 'add_path' => $destdir, + 'rename_files' => array( '.htaccess' => 'htaccess.bak', 'php.ini' => 'php.ini.bak' ), + 'skip_files' => array( basename(__FILE__), 'kickstart.php', 'abiautomation.ini', 'htaccess.bak', 'php.ini.bak' ) + ); + + if(!defined('KICKSTART')) + { + // In restore.php mode we have to exclude some more files + $config['skip_files'][] = 'administrator/components/com_akeeba/restore.php'; + $config['skip_files'][] = 'administrator/components/com_akeeba/restoration.php'; + } + + if(!empty($configOverride)) + { + foreach($configOverride as $key => $value) + { + $config[$key] = $value; + } + } + + $object->setup($config); + } + + return $object; + } + + /** + * Get the a reference to the Akeeba Engine's timer + * @return AKCoreTimer + */ + public static function &getTimer() + { + return self::getClassInstance('AKCoreTimer'); + } + +} + +/** + * AES implementation in PHP (c) Chris Veness 2005-2011 + * (http://www.movable-type.co.uk/scripts/aes-php.html) + * I offer these formulæ & scripts for free use and adaptation as my contribution to the + * open-source info-sphere from which I have received so much. You are welcome to re-use these + * scripts [under a simple attribution license or a GPL licence, without any warranty express or implied] + * provided solely that you retain my copyright notice and a link to this page. + * licence. No warranty of any form is offered. + * + * Modified for Akeeba Backup by Nicholas K. Dionysopoulos + */ +class AKEncryptionAES +{ + // Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [�5.1.1] + protected static $Sbox = + array(0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16); + + // Rcon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [�5.2] + protected static $Rcon = array( + array(0x00, 0x00, 0x00, 0x00), + array(0x01, 0x00, 0x00, 0x00), + array(0x02, 0x00, 0x00, 0x00), + array(0x04, 0x00, 0x00, 0x00), + array(0x08, 0x00, 0x00, 0x00), + array(0x10, 0x00, 0x00, 0x00), + array(0x20, 0x00, 0x00, 0x00), + array(0x40, 0x00, 0x00, 0x00), + array(0x80, 0x00, 0x00, 0x00), + array(0x1b, 0x00, 0x00, 0x00), + array(0x36, 0x00, 0x00, 0x00) ); + + protected static $passwords = array(); + + /** + * AES Cipher function: encrypt 'input' with Rijndael algorithm + * + * @param input message as byte-array (16 bytes) + * @param w key schedule as 2D byte-array (Nr+1 x Nb bytes) - + * generated from the cipher key by KeyExpansion() + * @return ciphertext as byte-array (16 bytes) + */ + protected static function Cipher($input, $w) { // main Cipher function [�5.1] + $Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES) + $Nr = count($w)/$Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys + + $state = array(); // initialise 4xNb byte-array 'state' with input [�3.4] + for ($i=0; $i<4*$Nb; $i++) $state[$i%4][floor($i/4)] = $input[$i]; + + $state = self::AddRoundKey($state, $w, 0, $Nb); + + for ($round=1; $round<$Nr; $round++) { // apply Nr rounds + $state = self::SubBytes($state, $Nb); + $state = self::ShiftRows($state, $Nb); + $state = self::MixColumns($state, $Nb); + $state = self::AddRoundKey($state, $w, $round, $Nb); + } + + $state = self::SubBytes($state, $Nb); + $state = self::ShiftRows($state, $Nb); + $state = self::AddRoundKey($state, $w, $Nr, $Nb); + + $output = array(4*$Nb); // convert state to 1-d array before returning [�3.4] + for ($i=0; $i<4*$Nb; $i++) $output[$i] = $state[$i%4][floor($i/4)]; + return $output; + } + + protected static function AddRoundKey($state, $w, $rnd, $Nb) { // xor Round Key into state S [�5.1.4] + for ($r=0; $r<4; $r++) { + for ($c=0; $c<$Nb; $c++) $state[$r][$c] ^= $w[$rnd*4+$c][$r]; + } + return $state; + } + + protected static function SubBytes($s, $Nb) { // apply SBox to state S [�5.1.1] + for ($r=0; $r<4; $r++) { + for ($c=0; $c<$Nb; $c++) $s[$r][$c] = self::$Sbox[$s[$r][$c]]; + } + return $s; + } + + protected static function ShiftRows($s, $Nb) { // shift row r of state S left by r bytes [�5.1.2] + $t = array(4); + for ($r=1; $r<4; $r++) { + for ($c=0; $c<4; $c++) $t[$c] = $s[$r][($c+$r)%$Nb]; // shift into temp copy + for ($c=0; $c<4; $c++) $s[$r][$c] = $t[$c]; // and copy back + } // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES): + return $s; // see fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf + } + + protected static function MixColumns($s, $Nb) { // combine bytes of each col of state S [�5.1.3] + for ($c=0; $c<4; $c++) { + $a = array(4); // 'a' is a copy of the current column from 's' + $b = array(4); // 'b' is a�{02} in GF(2^8) + for ($i=0; $i<4; $i++) { + $a[$i] = $s[$i][$c]; + $b[$i] = $s[$i][$c]&0x80 ? $s[$i][$c]<<1 ^ 0x011b : $s[$i][$c]<<1; + } + // a[n] ^ b[n] is a�{03} in GF(2^8) + $s[0][$c] = $b[0] ^ $a[1] ^ $b[1] ^ $a[2] ^ $a[3]; // 2*a0 + 3*a1 + a2 + a3 + $s[1][$c] = $a[0] ^ $b[1] ^ $a[2] ^ $b[2] ^ $a[3]; // a0 * 2*a1 + 3*a2 + a3 + $s[2][$c] = $a[0] ^ $a[1] ^ $b[2] ^ $a[3] ^ $b[3]; // a0 + a1 + 2*a2 + 3*a3 + $s[3][$c] = $a[0] ^ $b[0] ^ $a[1] ^ $a[2] ^ $b[3]; // 3*a0 + a1 + a2 + 2*a3 + } + return $s; + } + + /** + * Key expansion for Rijndael Cipher(): performs key expansion on cipher key + * to generate a key schedule + * + * @param key cipher key byte-array (16 bytes) + * @return key schedule as 2D byte-array (Nr+1 x Nb bytes) + */ + protected static function KeyExpansion($key) { // generate Key Schedule from Cipher Key [�5.2] + $Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES) + $Nk = count($key)/4; // key length (in words): 4/6/8 for 128/192/256-bit keys + $Nr = $Nk + 6; // no of rounds: 10/12/14 for 128/192/256-bit keys + + $w = array(); + $temp = array(); + + for ($i=0; $i<$Nk; $i++) { + $r = array($key[4*$i], $key[4*$i+1], $key[4*$i+2], $key[4*$i+3]); + $w[$i] = $r; + } + + for ($i=$Nk; $i<($Nb*($Nr+1)); $i++) { + $w[$i] = array(); + for ($t=0; $t<4; $t++) $temp[$t] = $w[$i-1][$t]; + if ($i % $Nk == 0) { + $temp = self::SubWord(self::RotWord($temp)); + for ($t=0; $t<4; $t++) $temp[$t] ^= self::$Rcon[$i/$Nk][$t]; + } else if ($Nk > 6 && $i%$Nk == 4) { + $temp = self::SubWord($temp); + } + for ($t=0; $t<4; $t++) $w[$i][$t] = $w[$i-$Nk][$t] ^ $temp[$t]; + } + return $w; + } + + protected static function SubWord($w) { // apply SBox to 4-byte word w + for ($i=0; $i<4; $i++) $w[$i] = self::$Sbox[$w[$i]]; + return $w; + } + + protected static function RotWord($w) { // rotate 4-byte word w left by one byte + $tmp = $w[0]; + for ($i=0; $i<3; $i++) $w[$i] = $w[$i+1]; + $w[3] = $tmp; + return $w; + } + + /* + * Unsigned right shift function, since PHP has neither >>> operator nor unsigned ints + * + * @param a number to be shifted (32-bit integer) + * @param b number of bits to shift a to the right (0..31) + * @return a right-shifted and zero-filled by b bits + */ + protected static function urs($a, $b) { + $a &= 0xffffffff; $b &= 0x1f; // (bounds check) + if ($a&0x80000000 && $b>0) { // if left-most bit set + $a = ($a>>1) & 0x7fffffff; // right-shift one bit & clear left-most bit + $a = $a >> ($b-1); // remaining right-shifts + } else { // otherwise + $a = ($a>>$b); // use normal right-shift + } + return $a; + } + + /** + * Encrypt a text using AES encryption in Counter mode of operation + * - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + * + * Unicode multi-byte character safe + * + * @param plaintext source text to be encrypted + * @param password the password to use to generate a key + * @param nBits number of bits to be used in the key (128, 192, or 256) + * @return encrypted text + */ + public static function AESEncryptCtr($plaintext, $password, $nBits) { + $blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES + if (!($nBits==128 || $nBits==192 || $nBits==256)) return ''; // standard allows 128/192/256 bit keys + // note PHP (5) gives us plaintext and password in UTF8 encoding! + + // use AES itself to encrypt password to get cipher key (using plain password as source for + // key expansion) - gives us well encrypted key + $nBytes = $nBits/8; // no bytes in key + $pwBytes = array(); + for ($i=0; $i<$nBytes; $i++) $pwBytes[$i] = ord(substr($password,$i,1)) & 0xff; + $key = self::Cipher($pwBytes, self::KeyExpansion($pwBytes)); + $key = array_merge($key, array_slice($key, 0, $nBytes-16)); // expand key to 16/24/32 bytes long + + // initialise counter block (NIST SP800-38A �B.2): millisecond time-stamp for nonce in + // 1st 8 bytes, block counter in 2nd 8 bytes + $counterBlock = array(); + $nonce = floor(microtime(true)*1000); // timestamp: milliseconds since 1-Jan-1970 + $nonceSec = floor($nonce/1000); + $nonceMs = $nonce%1000; + // encode nonce with seconds in 1st 4 bytes, and (repeated) ms part filling 2nd 4 bytes + for ($i=0; $i<4; $i++) $counterBlock[$i] = self::urs($nonceSec, $i*8) & 0xff; + for ($i=0; $i<4; $i++) $counterBlock[$i+4] = $nonceMs & 0xff; + // and convert it to a string to go on the front of the ciphertext + $ctrTxt = ''; + for ($i=0; $i<8; $i++) $ctrTxt .= chr($counterBlock[$i]); + + // generate key schedule - an expansion of the key into distinct Key Rounds for each round + $keySchedule = self::KeyExpansion($key); + + $blockCount = ceil(strlen($plaintext)/$blockSize); + $ciphertxt = array(); // ciphertext as array of strings + + for ($b=0; $b<$blockCount; $b++) { + // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes) + // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB) + for ($c=0; $c<4; $c++) $counterBlock[15-$c] = self::urs($b, $c*8) & 0xff; + for ($c=0; $c<4; $c++) $counterBlock[15-$c-4] = self::urs($b/0x100000000, $c*8); + + $cipherCntr = self::Cipher($counterBlock, $keySchedule); // -- encrypt counter block -- + + // block size is reduced on final block + $blockLength = $b<$blockCount-1 ? $blockSize : (strlen($plaintext)-1)%$blockSize+1; + $cipherByte = array(); + + for ($i=0; $i<$blockLength; $i++) { // -- xor plaintext with ciphered counter byte-by-byte -- + $cipherByte[$i] = $cipherCntr[$i] ^ ord(substr($plaintext, $b*$blockSize+$i, 1)); + $cipherByte[$i] = chr($cipherByte[$i]); + } + $ciphertxt[$b] = implode('', $cipherByte); // escape troublesome characters in ciphertext + } + + // implode is more efficient than repeated string concatenation + $ciphertext = $ctrTxt . implode('', $ciphertxt); + $ciphertext = base64_encode($ciphertext); + return $ciphertext; + } + + /** + * Decrypt a text encrypted by AES in counter mode of operation + * + * @param ciphertext source text to be decrypted + * @param password the password to use to generate a key + * @param nBits number of bits to be used in the key (128, 192, or 256) + * @return decrypted text + */ + public static function AESDecryptCtr($ciphertext, $password, $nBits) { + $blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES + if (!($nBits==128 || $nBits==192 || $nBits==256)) return ''; // standard allows 128/192/256 bit keys + $ciphertext = base64_decode($ciphertext); + + // use AES to encrypt password (mirroring encrypt routine) + $nBytes = $nBits/8; // no bytes in key + $pwBytes = array(); + for ($i=0; $i<$nBytes; $i++) $pwBytes[$i] = ord(substr($password,$i,1)) & 0xff; + $key = self::Cipher($pwBytes, self::KeyExpansion($pwBytes)); + $key = array_merge($key, array_slice($key, 0, $nBytes-16)); // expand key to 16/24/32 bytes long + + // recover nonce from 1st element of ciphertext + $counterBlock = array(); + $ctrTxt = substr($ciphertext, 0, 8); + for ($i=0; $i<8; $i++) $counterBlock[$i] = ord(substr($ctrTxt,$i,1)); + + // generate key schedule + $keySchedule = self::KeyExpansion($key); + + // separate ciphertext into blocks (skipping past initial 8 bytes) + $nBlocks = ceil((strlen($ciphertext)-8) / $blockSize); + $ct = array(); + for ($b=0; $b<$nBlocks; $b++) $ct[$b] = substr($ciphertext, 8+$b*$blockSize, 16); + $ciphertext = $ct; // ciphertext is now array of block-length strings + + // plaintext will get generated block-by-block into array of block-length strings + $plaintxt = array(); + + for ($b=0; $b<$nBlocks; $b++) { + // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes) + for ($c=0; $c<4; $c++) $counterBlock[15-$c] = self::urs($b, $c*8) & 0xff; + for ($c=0; $c<4; $c++) $counterBlock[15-$c-4] = self::urs(($b+1)/0x100000000-1, $c*8) & 0xff; + + $cipherCntr = self::Cipher($counterBlock, $keySchedule); // encrypt counter block + + $plaintxtByte = array(); + for ($i=0; $i $data_size) + { + $plaintext = substr($plaintext, 0, $data_size); + } + + return $plaintext; + } +} + +/** + * The Master Setup will read the configuration parameters from restoration.php, abiautomation.ini, or + * the JSON-encoded "configuration" input variable and return the status. + * @return bool True if the master configuration was applied to the Factory object + */ +function masterSetup() +{ + // ------------------------------------------------------------ + // 1. Import basic setup parameters + // ------------------------------------------------------------ + + $ini_data = null; + + // In restore.php mode, require restoration.php or fail + if(!defined('KICKSTART')) + { + // This is the standalone mode, used by Akeeba Backup Professional. It looks for a restoration.php + // file to perform its magic. If the file is not there, we will abort. + $setupFile = 'restoration.php'; + + if( !file_exists($setupFile) ) + { + // Uh oh... Somebody tried to pooh on our back yard. Lock the gates! Don't let the traitor inside! + AKFactory::set('kickstart.enabled', false); + return false; + } + + // Load restoration.php. It creates a global variable named $restoration_setup + require_once $setupFile; + $ini_data = $restoration_setup; + if(empty($ini_data)) + { + // No parameters fetched. Darn, how am I supposed to work like that?! + AKFactory::set('kickstart.enabled', false); + return false; + } + + AKFactory::set('kickstart.enabled', true); + } + else + { + // Maybe we have $restoration_setup defined in the head of kickstart.php + global $restoration_setup; + if(!empty($restoration_setup) && !is_array($restoration_setup)) { + $ini_data = AKText::parse_ini_file($restoration_setup, false, true); + } elseif(is_array($restoration_setup)) { + $ini_data = $restoration_setup; + } + } + + // Import any data from $restoration_setup + if(!empty($ini_data)) + { + foreach($ini_data as $key => $value) + { + AKFactory::set($key, $value); + } + AKFactory::set('kickstart.enabled', true); + } + + // Reinitialize $ini_data + $ini_data = null; + + // ------------------------------------------------------------ + // 2. Explode JSON parameters into $_REQUEST scope + // ------------------------------------------------------------ + + // Detect a JSON string in the request variable and store it. + $json = getQueryParam('json', null); + + // Remove everything from the request array + if(!empty($_REQUEST)) + { + foreach($_REQUEST as $key => $value) + { + unset($_REQUEST[$key]); + } + } + // Decrypt a possibly encrypted JSON string + if(!empty($json)) + { + $password = AKFactory::get('kickstart.security.password', null); + if(!empty($password)) + { + $json = AKEncryptionAES::AESDecryptCtr($json, $password, 128); + } + + // Get the raw data + $raw = json_decode( $json, true ); + // Pass all JSON data to the request array + if(!empty($raw)) + { + foreach($raw as $key => $value) + { + $_REQUEST[$key] = $value; + } + } + } + + // ------------------------------------------------------------ + // 3. Try the "factory" variable + // ------------------------------------------------------------ + // A "factory" variable will override all other settings. + $serialized = getQueryParam('factory', null); + if( !is_null($serialized) ) + { + // Get the serialized factory + AKFactory::unserialize($serialized); + AKFactory::set('kickstart.enabled', true); + return true; + } + + // ------------------------------------------------------------ + // 4. Try abiautomation.ini and the configuration variable for Kickstart + // ------------------------------------------------------------ + if(defined('KICKSTART')) + { + // We are in Kickstart mode. abiautomation.ini has precedence. + $setupFile = 'abiautomation.ini'; + if( file_exists($setupFile) ) + { + // abiautomation.ini was found + $ini_data = AKText::parse_ini_file('restoration.ini', false); + } + else + { + // abiautomation.ini was not found. Let's try input parameters. + $configuration = getQueryParam('configuration'); + if( !is_null($configuration) ) + { + // Let's decode the configuration from JSON to array + $ini_data = json_decode($configuration, true); + } + else + { + // Neither exists. Enable Kickstart's interface anyway. + $ini_data = array('kickstart.enabled'=>true); + } + } + + // Import any INI data we might have from other sources + if(!empty($ini_data)) + { + foreach($ini_data as $key => $value) + { + AKFactory::set($key, $value); + } + AKFactory::set('kickstart.enabled', true); + return true; + } + } +} + +// Mini-controller for restore.php +if(!defined('KICKSTART')) +{ + // The observer class, used to report number of files and bytes processed + class RestorationObserver extends AKAbstractPartObserver + { + public $compressedTotal = 0; + public $uncompressedTotal = 0; + public $filesProcessed = 0; + + public function update($object, $message) + { + if(!is_object($message)) return; + + if( !array_key_exists('type', get_object_vars($message)) ) return; + + if( $message->type == 'startfile' ) + { + $this->filesProcessed++; + $this->compressedTotal += $message->content->compressed; + $this->uncompressedTotal += $message->content->uncompressed; + } + } + + public function __toString() + { + return __CLASS__; + } + + } + + // Import configuration + masterSetup(); + + $retArray = array( + 'status' => true, + 'message' => null + ); + + $enabled = AKFactory::get('kickstart.enabled', false); + + if($enabled) + { + $task = getQueryParam('task'); + + switch($task) + { + case 'ping': + // ping task - realy does nothing! + $timer = AKFactory::getTimer(); + $timer->enforce_min_exec_time(); + break; + + case 'startRestore': + AKFactory::nuke(); // Reset the factory + + // Let the control flow to the next step (the rest of the code is common!!) + + case 'stepRestore': + $engine = AKFactory::getUnarchiver(); // Get the engine + $observer = new RestorationObserver(); // Create a new observer + $engine->attach($observer); // Attach the observer + $engine->tick(); + $ret = $engine->getStatusArray(); + + if( $ret['Error'] != '' ) + { + $retArray['status'] = false; + $retArray['done'] = true; + $retArray['message'] = $ret['Error']; + } + elseif( !$ret['HasRun'] ) + { + $retArray['files'] = $observer->filesProcessed; + $retArray['bytesIn'] = $observer->compressedTotal; + $retArray['bytesOut'] = $observer->uncompressedTotal; + $retArray['status'] = true; + $retArray['done'] = true; + } + else + { + $retArray['files'] = $observer->filesProcessed; + $retArray['bytesIn'] = $observer->compressedTotal; + $retArray['bytesOut'] = $observer->uncompressedTotal; + $retArray['status'] = true; + $retArray['done'] = false; + $retArray['factory'] = AKFactory::serialize(); + } + break; + + case 'finalizeRestore': + $root = AKFactory::get('kickstart.setup.destdir'); + // Remove the installation directory + recursive_remove_directory( $root.'/installation' ); + + $postproc = AKFactory::getPostProc(); + + // Rename htaccess.bak to .htaccess + if(file_exists($root.'/htaccess.bak')) + { + if( file_exists($root.'/.htaccess') ) + { + $postproc->unlink($root.'/.htaccess'); + } + $postproc->rename( $root.'/htaccess.bak', $root.'/.htaccess' ); + } + + // Remove restoration.php + $basepath = dirname(__FILE__); + $basepath = rtrim( str_replace('\\','/',$basepath), '/' ); + if(!empty($basepath)) $basepath .= '/'; + $postproc->unlink( $basepath.'restoration.php' ); + break; + + default: + // Invalid task! + $enabled = false; + break; + } + } + + // Maybe we weren't authorized or the task was invalid? + if(!$enabled) + { + // Maybe the user failed to enter any information + $retArray['status'] = false; + $retArray['message'] = AKText::_('ERR_INVALID_LOGIN'); + } + + // JSON encode the message + $json = json_encode($retArray); + // Do I have to encrypt? + $password = AKFactory::get('kickstart.security.password', null); + if(!empty($password)) + { + $json = AKEncryptionAES::AESEncryptCtr($json, $password, 128); + } + + // Return the message + echo "###$json###"; + +} + +// ------------ lixlpixel recursive PHP functions ------------- +// recursive_remove_directory( directory to delete, empty ) +// expects path to directory and optional TRUE / FALSE to empty +// of course PHP has to have the rights to delete the directory +// you specify and all files and folders inside the directory +// ------------------------------------------------------------ +function recursive_remove_directory($directory) +{ + // if the path has a slash at the end we remove it here + if(substr($directory,-1) == '/') + { + $directory = substr($directory,0,-1); + } + // if the path is not valid or is not a directory ... + if(!file_exists($directory) || !is_dir($directory)) + { + // ... we return false and exit the function + return FALSE; + // ... if the path is not readable + }elseif(!is_readable($directory)) + { + // ... we return false and exit the function + return FALSE; + // ... else if the path is readable + }else{ + // we open the directory + $handle = opendir($directory); + $postproc = AKFactory::getPostProc(); + // and scan through the items inside + while (FALSE !== ($item = readdir($handle))) + { + // if the filepointer is not the current directory + // or the parent directory + if($item != '.' && $item != '..') + { + // we build the new path to delete + $path = $directory.'/'.$item; + // if the new path is a directory + if(is_dir($path)) + { + // we call this function with the new path + recursive_remove_directory($path); + // if the new path is a file + }else{ + // we remove the file + $postproc->unlink($path); + } + } + } + // close the directory + closedir($handle); + // try to delete the now empty directory + if(!$postproc->rmdir($directory)) + { + // return false if not possible + return FALSE; + } + // return success + return TRUE; + } +} +?> \ No newline at end of file diff --git a/administrator/components/com_joomlaupdate/views/default/index.html b/administrator/components/com_joomlaupdate/views/default/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_joomlaupdate/views/default/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_joomlaupdate/views/default/tmpl/complete.php b/administrator/components/com_joomlaupdate/views/default/tmpl/complete.php new file mode 100644 index 0000000..06df3ad --- /dev/null +++ b/administrator/components/com_joomlaupdate/views/default/tmpl/complete.php @@ -0,0 +1,20 @@ + + +
+ + + +

+ +

+
diff --git a/administrator/components/com_joomlaupdate/views/default/tmpl/default.php b/administrator/components/com_joomlaupdate/views/default/tmpl/default.php new file mode 100644 index 0000000..b6fffa5 --- /dev/null +++ b/administrator/components/com_joomlaupdate/views/default/tmpl/default.php @@ -0,0 +1,139 @@ +ftp['enabled'] ? '' : 'style = "display: none"'; + +?> + +
+ +updateInfo['object'])) : ?> + +
+ + + +

+ +

+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + > + + + + > + + + + > + + + + > + + + + > + + + + + + + + + + +
+ + + updateInfo['installed'] ?> +
+ + + updateInfo['latest'] ?> +
+ + + + updateInfo['object']->downloadurl->_data ?> + +
+ + + methodSelect ?> +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+   + + +
+
+ + + + + + +
+ + diff --git a/administrator/components/com_joomlaupdate/views/default/tmpl/index.html b/administrator/components/com_joomlaupdate/views/default/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_joomlaupdate/views/default/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_joomlaupdate/views/default/view.html.php b/administrator/components/com_joomlaupdate/views/default/view.html.php new file mode 100644 index 0000000..92082a4 --- /dev/null +++ b/administrator/components/com_joomlaupdate/views/default/view.html.php @@ -0,0 +1,68 @@ +state = $this->get('State'); + + // Load useful classes + $model = $this->getModel(); + $this->loadHelper('select'); + + // Assign view variables + $ftp = $model->getFTPOptions(); + $this->assign('updateInfo', $model->getUpdateInformation()); + $this->assign('methodSelect', JoomlaupdateHelperSelect::getMethods($ftp['enabled'])); + + // Set the toolbar information + JToolbarHelper::title(JText::_('COM_JOOMLAUPDATE_OVERVIEW'), 'install'); + JToolbarHelper::custom('update.purge', 'purge', 'purge', 'JTOOLBAR_PURGE_CACHE', false, false); + + // Add toolbar buttons + if (JFactory::getUser()->authorise('core.admin', 'com_joomlaupdate')) + { + JToolbarHelper::preferences('com_joomlaupdate'); + } + JToolBarHelper::divider(); + JToolBarHelper::help('JHELP_COMPONENTS_JOOMLA_UPDATE'); + + // Load mooTools + JHtml::_('behavior.framework', true); + + // Load our Javascript + $document = JFactory::getDocument(); + $document->addScript('../media/com_joomlaupdate/default.js'); + JHtml::_('stylesheet', 'media/mediamanager.css', array(), true); + + // Render the view + parent::display($tpl); + } + +} diff --git a/administrator/components/com_joomlaupdate/views/index.html b/administrator/components/com_joomlaupdate/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_joomlaupdate/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_joomlaupdate/views/update/index.html b/administrator/components/com_joomlaupdate/views/update/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_joomlaupdate/views/update/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_joomlaupdate/views/update/tmpl/default.php b/administrator/components/com_joomlaupdate/views/update/tmpl/default.php new file mode 100644 index 0000000..2e1c219 --- /dev/null +++ b/administrator/components/com_joomlaupdate/views/update/tmpl/default.php @@ -0,0 +1,43 @@ + + +

+
+ +
+
+
+ 'progress', 'id' => 'progress'), true + ); ?> +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
diff --git a/administrator/components/com_joomlaupdate/views/update/tmpl/index.html b/administrator/components/com_joomlaupdate/views/update/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_joomlaupdate/views/update/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_joomlaupdate/views/update/view.html.php b/administrator/components/com_joomlaupdate/views/update/view.html.php new file mode 100644 index 0000000..f005bea --- /dev/null +++ b/administrator/components/com_joomlaupdate/views/update/view.html.php @@ -0,0 +1,70 @@ +getUserState('com_joomlaupdate.password', null); + $filesize = JFactory::getApplication()->getUserState('com_joomlaupdate.filesize', null); + $ajaxUrl = JUri::base().'components/com_joomlaupdate/restore.php'; + $returnUrl = 'index.php?option=com_joomlaupdate&task=update.finalise'; + + // Set the toolbar information + JToolbarHelper::title(JText::_('COM_JOOMLAUPDATE_OVERVIEW'), 'install'); + JToolBarHelper::divider(); + JToolBarHelper::help('JHELP_COMPONENTS_JOOMLA_UPDATE'); + + // Add toolbar buttons + if (JFactory::getUser()->authorise('core.admin', 'com_joomlaupdate')) + { + JToolbarHelper::preferences('com_joomlaupdate'); + } + + // Load mooTools + JHtml::_('behavior.framework', true); + + $updateScript = <<addScript('../media/com_joomlaupdate/json2.js'); + $document->addScript('../media/com_joomlaupdate/encryption.js'); + $document->addScript('../media/com_joomlaupdate/update.js'); + JHtml::_('script', 'system/progressbar.js', true, true); + JHtml::_('stylesheet', 'media/mediamanager.css', array(), true); + $document->addScriptDeclaration($updateScript); + + // Render the view + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/access.xml b/administrator/components/com_k2/access.xml new file mode 100644 index 0000000..d821949 --- /dev/null +++ b/administrator/components/com_k2/access.xml @@ -0,0 +1,12 @@ + + +
+ + + + + + + +
+
diff --git a/administrator/components/com_k2/config.xml b/administrator/components/com_k2/config.xml new file mode 100644 index 0000000..7ead9a8 --- /dev/null +++ b/administrator/components/com_k2/config.xml @@ -0,0 +1,1134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
diff --git a/administrator/components/com_k2/controllers/categories.php b/administrator/components/com_k2/controllers/categories.php new file mode 100644 index 0000000..84d460a --- /dev/null +++ b/administrator/components/com_k2/controllers/categories.php @@ -0,0 +1,151 @@ +getModel('categories'); + $model->publish(); + } + + function unpublish() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('categories'); + $model->unpublish(); + } + + function saveorder() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('categories'); + $model->saveorder(); + $document = JFactory::getDocument(); + if ($document->getType() == 'raw') + { + echo '1'; + return $this; + } + else + { + $this->setRedirect('index.php?option=com_k2&view=categories', JText::_('K2_NEW_ORDERING_SAVED')); + } + } + + function orderup() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('categories'); + $model->orderup(); + } + + function orderdown() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('categories'); + $model->orderdown(); + } + + function accessregistered() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('categories'); + $model->accessregistered(); + } + + function accessspecial() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('categories'); + $model->accessspecial(); + } + + function accesspublic() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('categories'); + $model->accesspublic(); + } + + function trash() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('categories'); + $model->trash(); + } + + function restore() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('categories'); + $model->restore(); + } + + function remove() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('categories'); + $model->remove(); + } + + function add() + { + $mainframe = JFactory::getApplication(); + $mainframe->redirect('index.php?option=com_k2&view=category'); + } + + function edit() + { + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $mainframe->redirect('index.php?option=com_k2&view=category&cid='.$cid[0]); + } + + function element() + { + JRequest::setVar('view', 'categories'); + JRequest::setVar('layout', 'element'); + parent::display(); + } + + function move() + { + $view = $this->getView('categories', 'html'); + $view->setLayout('move'); + $view->move(); + } + + function saveMove() + { + $model = $this->getModel('categories'); + $model->move(); + } + + function copy() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('categories'); + $model->copy(); + } + +} diff --git a/administrator/components/com_k2/controllers/category.php b/administrator/components/com_k2/controllers/category.php new file mode 100644 index 0000000..ccf8227 --- /dev/null +++ b/administrator/components/com_k2/controllers/category.php @@ -0,0 +1,49 @@ +getModel('category'); + $model->save(); + } + + function saveAndNew() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('category'); + $model->save(); + } + + function apply() + { + $this->save(); + } + + function cancel() + { + $mainframe = JFactory::getApplication(); + $mainframe->redirect('index.php?option=com_k2&view=categories'); + } + +} diff --git a/administrator/components/com_k2/controllers/comments.php b/administrator/components/com_k2/controllers/comments.php new file mode 100644 index 0000000..812bc13 --- /dev/null +++ b/administrator/components/com_k2/controllers/comments.php @@ -0,0 +1,60 @@ +getModel('comments'); + $model->publish(); + } + + function unpublish() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('comments'); + $model->unpublish(); + } + + function remove() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('comments'); + $model->remove(); + } + + function deleteUnpublished() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('comments'); + $model->deleteUnpublished(); + } + + function saveComment() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('comments'); + $model->save(); + } + +} diff --git a/administrator/components/com_k2/controllers/controller.php b/administrator/components/com_k2/controllers/controller.php new file mode 100644 index 0000000..90fc0b0 --- /dev/null +++ b/administrator/components/com_k2/controllers/controller.php @@ -0,0 +1,49 @@ +getModel('extraField'); + $model->save(); + } + + function apply() + { + $this->save(); + } + + function cancel() + { + $mainframe = JFactory::getApplication(); + $mainframe->redirect('index.php?option=com_k2&view=extrafields'); + } + +} diff --git a/administrator/components/com_k2/controllers/extrafields.php b/administrator/components/com_k2/controllers/extrafields.php new file mode 100644 index 0000000..e1317ba --- /dev/null +++ b/administrator/components/com_k2/controllers/extrafields.php @@ -0,0 +1,89 @@ +getModel('extraFields'); + $model->publish(); + } + + function unpublish() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('extraFields'); + $model->unpublish(); + } + + function saveorder() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('extraFields'); + $model->saveorder(); + $document = JFactory::getDocument(); + if ($document->getType() == 'raw') + { + echo '1'; + return $this; + } + else + { + $this->setRedirect('index.php?option=com_k2&view=extrafields', JText::_('K2_NEW_ORDERING_SAVED')); + } + } + + function orderup() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('extraFields'); + $model->orderup(); + } + + function orderdown() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('extraFields'); + $model->orderdown(); + } + + function remove() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('extraFields'); + $model->remove(); + } + + function add() + { + $mainframe = JFactory::getApplication(); + $mainframe->redirect('index.php?option=com_k2&view=extrafield'); + } + + function edit() + { + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $mainframe->redirect('index.php?option=com_k2&view=extrafield&cid='.$cid[0]); + } + +} diff --git a/administrator/components/com_k2/controllers/extrafieldsgroup.php b/administrator/components/com_k2/controllers/extrafieldsgroup.php new file mode 100644 index 0000000..72b5cfb --- /dev/null +++ b/administrator/components/com_k2/controllers/extrafieldsgroup.php @@ -0,0 +1,47 @@ +getModel('extraFields'); + $view = $this->getView('extrafieldsgroup', 'html'); + $view->setModel($model, true); + parent::display(); + } + + function save() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('extraFields'); + $view = $this->getView('extrafieldsgroup', 'html'); + $view->setModel($model, true); + $model->saveGroup(); + } + + function apply() + { + $this->save(); + } + + function cancel() + { + $mainframe = JFactory::getApplication(); + $mainframe->redirect('index.php?option=com_k2&view=extrafieldsgroups'); + } + +} diff --git a/administrator/components/com_k2/controllers/extrafieldsgroups.php b/administrator/components/com_k2/controllers/extrafieldsgroups.php new file mode 100644 index 0000000..1055b05 --- /dev/null +++ b/administrator/components/com_k2/controllers/extrafieldsgroups.php @@ -0,0 +1,47 @@ +getModel('extraFields'); + $view = $this->getView('extrafieldsgroups', 'html'); + $view->setModel($model, true); + parent::display(); + } + + function add() + { + $mainframe = JFactory::getApplication(); + $mainframe->redirect('index.php?option=com_k2&view=extrafieldsgroup'); + } + + function edit() + { + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $mainframe->redirect('index.php?option=com_k2&view=extrafieldsgroup&cid='.$cid[0]); + } + + function remove() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('extraFields'); + $model->removeGroups(); + } + +} diff --git a/administrator/components/com_k2/controllers/info.php b/administrator/components/com_k2/controllers/info.php new file mode 100644 index 0000000..a75d7ef --- /dev/null +++ b/administrator/components/com_k2/controllers/info.php @@ -0,0 +1,24 @@ +getModel('item'); + $model->save(); + } + + function apply() + { + $this->save(); + } + + function cancel() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('item'); + $model->cancel(); + } + + function deleteAttachment() + { + $model = $this->getModel('item'); + $model->deleteAttachment(); + } + + function tag() + { + $model = $this->getModel('tag'); + $model->addTag(); + } + + function download() + { + $model = $this->getModel('item'); + $model->download(); + } + + function extraFields() + { + $mainframe = JFactory::getApplication(); + $itemID = JRequest::getInt('id', NULL); + $categoryModel = $this->getModel('category'); + $category = $categoryModel->getData(); + $extraFieldModel = $this->getModel('extraField'); + $extraFields = $extraFieldModel->getExtraFieldsByGroup($category->extraFieldsGroup); + + $output = ''; + $counter = 0; + if (count($extraFields)) + { + foreach ($extraFields as $extraField) + { + + if ($extraField->type == 'header') + { + $output .= ''; + } + else + { + $output .= ''; + $output .= ''; + } + $counter++; + } + } + $output .= '

'.$extraField->name.'

'.$extraFieldModel->renderExtraField($extraField, $itemID).'
'; + + if ($counter == 0) + $output = JText::_('K2_THIS_CATEGORY_DOESNT_HAVE_ASSIGNED_EXTRA_FIELDS'); + + echo $output; + + $mainframe->close(); + } + + function resetHits() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('item'); + $model->resetHits(); + + } + + function resetRating() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('item'); + $model->resetRating(); + + } + +} diff --git a/administrator/components/com_k2/controllers/items.php b/administrator/components/com_k2/controllers/items.php new file mode 100644 index 0000000..1839270 --- /dev/null +++ b/administrator/components/com_k2/controllers/items.php @@ -0,0 +1,202 @@ +getModel('items'); + $model->publish(); + } + + function unpublish() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $model->unpublish(); + } + + function saveorder() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $result = $model->saveorder(); + $document = JFactory::getDocument(); + if ($document->getType() == 'raw') + { + echo '1'; + return $this; + } + else + { + $this->setRedirect('index.php?option=com_k2&view=items', JText::_('K2_NEW_ORDERING_SAVED')); + } + } + + function orderup() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $model->orderup(); + } + + function orderdown() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $model->orderdown(); + } + + function savefeaturedorder() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $result = $model->savefeaturedorder(); + $document = JFactory::getDocument(); + if ($document->getType() == 'raw') + { + echo '1'; + return $this; + } + else + { + $this->setRedirect('index.php?option=com_k2&view=items', JText::_('K2_NEW_FEATURED_ORDERING_SAVED')); + } + } + + function featuredorderup() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $model->featuredorderup(); + } + + function featuredorderdown() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $model->featuredorderdown(); + } + + function accessregistered() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $model->accessregistered(); + } + + function accessspecial() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $model->accessspecial(); + } + + function accesspublic() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $model->accesspublic(); + } + + function featured() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $model->featured(); + } + + function trash() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $model->trash(); + } + + function restore() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $model->restore(); + } + + function remove() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $model->remove(); + } + + function add() + { + $mainframe = JFactory::getApplication(); + $mainframe->redirect('index.php?option=com_k2&view=item'); + } + + function edit() + { + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $mainframe->redirect('index.php?option=com_k2&view=item&cid='.$cid[0]); + } + + function copy() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('items'); + $model->copy(); + } + + function element() + { + JRequest::setVar('view', 'items'); + JRequest::setVar('layout', 'element'); + parent::display(); + } + + function import() + { + $model = $this->getModel('items'); + if (K2_JVERSION != '15') + { + $model->importJ16(); + } + else + { + $model->import(); + } + } + + function move() + { + $view = $this->getView('items', 'html'); + $view->setLayout('move'); + $view->move(); + } + + function saveMove() + { + $model = $this->getModel('items'); + $model->move(); + } + +} diff --git a/administrator/components/com_k2/controllers/media.php b/administrator/components/com_k2/controllers/media.php new file mode 100644 index 0000000..5b0807e --- /dev/null +++ b/administrator/components/com_k2/controllers/media.php @@ -0,0 +1,82 @@ +get('file_path', 'media'); + $folder = JRequest::getVar('folder', $root, 'default', 'path'); + $type = JRequest::getCmd('type', 'video'); + if (JString::trim($folder) == "") + { + $folder = $root; + } + $url = JURI::root(true).'/'.$folder; + $path = JPATH_SITE.DS.JPath::clean($folder); + JPath::check($path); + include_once JPATH_COMPONENT_ADMINISTRATOR.DS.'lib'.DS.'elfinder'.DS.'elFinderConnector.class.php'; + include_once JPATH_COMPONENT_ADMINISTRATOR.DS.'lib'.DS.'elfinder'.DS.'elFinder.class.php'; + include_once JPATH_COMPONENT_ADMINISTRATOR.DS.'lib'.DS.'elfinder'.DS.'elFinderVolumeDriver.class.php'; + include_once JPATH_COMPONENT_ADMINISTRATOR.DS.'lib'.DS.'elfinder'.DS.'elFinderVolumeLocalFileSystem.class.php'; + function access($attr, $path, $data, $volume) + { + $mainframe = JFactory::getApplication(); + // Hide files and folders starting with . + if (strpos(basename($path), '.') === 0 && $attr == 'hidden') + { + return true; + } + // Read only access for front-end. Full access for administration section. + switch($attr) + { + case 'read' : + return true; + break; + case 'write' : + return ($mainframe->isSite()) ? false : true; + break; + case 'locked' : + return ($mainframe->isSite()) ? true : false; + break; + case 'hidden' : + return false; + break; + } + + } + + if ($mainframe->isAdmin()) + { + $permissions = array('read' => true, 'write' => true); + } + else + { + $permissions = array('read' => true, 'write' => false); + } + $options = array('roots' => array( array('driver' => 'LocalFileSystem', 'path' => $path, 'URL' => $url, 'accessControl' => 'access', 'defaults' => $permissions))); + $connector = new elFinderConnector(new elFinder($options)); + $connector->run(); + } + +} diff --git a/administrator/components/com_k2/controllers/settings.php b/administrator/components/com_k2/controllers/settings.php new file mode 100644 index 0000000..fa7500d --- /dev/null +++ b/administrator/components/com_k2/controllers/settings.php @@ -0,0 +1,42 @@ +redirect('index.php?option=com_config&view=component&component=com_k2&path=&tmpl=component'); + } + else + { + JRequest::setVar('tmpl', 'component'); + parent::display(); + } + } + + function save() + { + $mainframe = JFactory::getApplication(); + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('settings'); + $model->save(); + $mainframe->redirect('index.php?option=com_k2&view=settings'); + + } + +} diff --git a/administrator/components/com_k2/controllers/tag.php b/administrator/components/com_k2/controllers/tag.php new file mode 100644 index 0000000..7653710 --- /dev/null +++ b/administrator/components/com_k2/controllers/tag.php @@ -0,0 +1,42 @@ +getModel('tag'); + $model->save(); + } + + function apply() + { + $this->save(); + } + + function cancel() + { + $mainframe = JFactory::getApplication(); + $mainframe->redirect('index.php?option=com_k2&view=tags'); + } + +} diff --git a/administrator/components/com_k2/controllers/tags.php b/administrator/components/com_k2/controllers/tags.php new file mode 100644 index 0000000..14d51f4 --- /dev/null +++ b/administrator/components/com_k2/controllers/tags.php @@ -0,0 +1,72 @@ +getModel('tags'); + $model->publish(); + } + + function unpublish() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('tags'); + $model->unpublish(); + } + + function remove() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('tags'); + $model->remove(); + } + + function add() + { + $mainframe = JFactory::getApplication(); + $mainframe->redirect('index.php?option=com_k2&view=tag'); + } + + function edit() + { + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $mainframe->redirect('index.php?option=com_k2&view=tag&cid='.$cid[0]); + } + + function element() + { + JRequest::setVar('view', 'tags'); + JRequest::setVar('layout', 'element'); + parent::display(); + } + + function removeOrphans() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('tags'); + $model->removeOrphans(); + } + +} diff --git a/administrator/components/com_k2/controllers/user.php b/administrator/components/com_k2/controllers/user.php new file mode 100644 index 0000000..1e0bf72 --- /dev/null +++ b/administrator/components/com_k2/controllers/user.php @@ -0,0 +1,50 @@ +getModel('user'); + $model->save(); + } + + function apply() + { + $this->save(); + } + + function cancel() + { + $mainframe = JFactory::getApplication(); + $mainframe->redirect('index.php?option=com_k2&view=users'); + } + + function report() + { + $model = K2Model::getInstance('User', 'K2Model'); + $model->setState('id', JRequest::getInt('id')); + $model->reportSpammer(); + $this->setRedirect('index.php?option=com_k2&view=users'); + } + +} diff --git a/administrator/components/com_k2/controllers/usergroup.php b/administrator/components/com_k2/controllers/usergroup.php new file mode 100644 index 0000000..6627080 --- /dev/null +++ b/administrator/components/com_k2/controllers/usergroup.php @@ -0,0 +1,42 @@ +getModel('userGroup'); + $model->save(); + } + + function apply() + { + $this->save(); + } + + function cancel() + { + $mainframe = JFactory::getApplication(); + $mainframe->redirect('index.php?option=com_k2&view=usergroups'); + } + +} diff --git a/administrator/components/com_k2/controllers/usergroups.php b/administrator/components/com_k2/controllers/usergroups.php new file mode 100644 index 0000000..6a63d35 --- /dev/null +++ b/administrator/components/com_k2/controllers/usergroups.php @@ -0,0 +1,44 @@ +redirect('index.php?option=com_k2&view=usergroup&cid='.$cid[0]); + } + + function add() + { + $mainframe = JFactory::getApplication(); + $mainframe->redirect('index.php?option=com_k2&view=usergroup'); + } + + function remove() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('userGroups'); + $model->remove(); + } + +} diff --git a/administrator/components/com_k2/controllers/users.php b/administrator/components/com_k2/controllers/users.php new file mode 100644 index 0000000..2829fe4 --- /dev/null +++ b/administrator/components/com_k2/controllers/users.php @@ -0,0 +1,88 @@ +redirect('index.php?option=com_k2&view=user&cid='.$cid[0]); + } + + function remove() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('users'); + $model->remove(); + } + + function element() + { + JRequest::setVar('view', 'users'); + JRequest::setVar('layout', 'element'); + parent::display(); + } + + function enable() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('users'); + $model->enable(); + } + + function disable() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('users'); + $model->disable(); + } + + function delete() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('users'); + $model->delete(); + } + + function move() + { + $view = $this->getView('users', 'html'); + $view->setLayout('move'); + $model = $this->getModel('users'); + $view->setModel($model); + $view->move(); + } + + function saveMove() + { + JRequest::checkToken() or jexit('Invalid Token'); + $model = $this->getModel('users'); + $model->saveMove(); + } + + function import() + { + $model = $this->getModel('users'); + $model->import(); + } + +} diff --git a/administrator/components/com_k2/elements/base.php b/administrator/components/com_k2/elements/base.php new file mode 100644 index 0000000..d7e923b --- /dev/null +++ b/administrator/components/com_k2/elements/base.php @@ -0,0 +1,52 @@ +fetchElement($this->name, $this->value, $this->element, $this->options['control']); + } + + function getLabel() + { + if (method_exists($this, 'fetchTooltip')) + { + return $this->fetchTooltip($this->element['label'], $this->description, $this->element, $this->options['control'], $this->element['name'] = ''); + } + else + { + return parent::getLabel(); + } + + } + + function render() + { + return $this->getInput(); + } + + } + +} diff --git a/administrator/components/com_k2/elements/categories.php b/administrator/components/com_k2/elements/categories.php new file mode 100644 index 0000000..3e912a1 --- /dev/null +++ b/administrator/components/com_k2/elements/categories.php @@ -0,0 +1,94 @@ +setQuery($query); + $mitems = $db->loadObjectList(); + $children = array(); + if ($mitems) + { + foreach ($mitems as $v) + { + if (K2_JVERSION != '15') + { + $v->title = $v->name; + $v->parent_id = $v->parent; + } + $pt = $v->parent; + $list = @$children[$pt] ? $children[$pt] : array(); + array_push($list, $v); + $children[$pt] = $list; + } + } + $list = JHTML::_('menu.treerecurse', 0, '', array(), $children, 9999, 0, 0); + $mitems = array(); + $mitems[] = JHTML::_('select.option', '0', JText::_('K2_NONE_ONSELECTLISTS')); + + foreach ($list as $item) + { + $item->treename = JString::str_ireplace(' ', ' -', $item->treename); + $mitems[] = JHTML::_('select.option', $item->id, $item->treename); + } + + $attributes = 'class="inputbox"'; + if (K2_JVERSION != '15') + { + $attribute = K2_JVERSION == '25' ? $node->getAttribute('multiple') : $node->attributes()->multiple; + if ($attribute) + { + $attributes .= ' multiple="multiple" size="10"'; + } + } + else + { + if ($node->attributes('multiple')) + { + $attributes .= ' multiple="multiple" size="10"'; + } + } + + if (K2_JVERSION != '15') + { + $fieldName = $name; + } + else + { + $fieldName = $control_name.'['.$name.']'; + if ($node->attributes('multiple')) + { + $fieldName .= '[]'; + } + } + + return JHTML::_('select.genericlist', $mitems, $fieldName, $attributes, 'value', 'text', $value); + } + +} + +class JFormFieldCategories extends K2ElementCategories +{ + var $type = 'categories'; +} + +class JElementCategories extends K2ElementCategories +{ + var $_name = 'categories'; +} diff --git a/administrator/components/com_k2/elements/categorieslatest.php b/administrator/components/com_k2/elements/categorieslatest.php new file mode 100644 index 0000000..771ccc2 --- /dev/null +++ b/administrator/components/com_k2/elements/categorieslatest.php @@ -0,0 +1,139 @@ +attributes()->multiple) + { + $fieldName .= '[]'; + } + $image = JURI::root(true).'/administrator/templates/'.$mainframe->getTemplate().'/images/admin/publish_x.png'; + } + else + { + $fieldName = $control_name.'['.$name.'][]'; + $image = JURI::root(true).'/administrator/images/publish_x.png'; + } + + $js = " + function jSelectCategory(id, title, object) { + var exists = false; + \$K2('#categoriesList input').each(function(){ + if(\$K2(this).val()==id){ + alert('".JText::_('K2_THE_SELECTED_CATEGORY_IS_ALREADY_IN_THE_LIST', true)."'); + exists = true; + } + }); + if(!exists){ + var container = \$K2('
  • ').appendTo(\$K2('#categoriesList')); + var img = \$K2('',{'class':'remove', src:'".$image."'}).appendTo(container); + img.click(function(){\$K2(this).parent().remove();}); + var span = \$K2('',{'class':'handle'}).html(title).appendTo(container); + var input = \$K2('',{value:id, type:'hidden', name:'".$fieldName."'}).appendTo(container); + var div = \$K2('
    ',{style:'clear:both;'}).appendTo(container); + \$K2('#categoriesList').sortable('refresh'); + alert('".JText::_('K2_CATEGORY_ADDED_IN_THE_LIST', true)."'); + } + } + + \$K2(document).ready(function(){ + \$K2('#categoriesList').sortable({ + containment: '#categoriesList', + items: 'li', + handle: 'span.handle' + }); + \$K2('body').css('overflow-y', 'scroll'); + \$K2('#categoriesList .remove').click(function(){ + \$K2(this).parent().remove(); + }); + }); + "; + + $document->addScriptDeclaration($js); + $document->addStyleSheet(JURI::root(true).'/media/k2/assets/css/k2.modules.css?v=2.6.7'); + + $current = array(); + if (is_string($value) && !empty($value)) + { + $current[] = $value; + } + if (is_array($value)) + { + $current = $value; + } + + $output = ' + +
    + '; + + JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_k2'.DS.'tables'); + + $output .= '
      '; + foreach ($current as $id) + { + $row = JTable::getInstance('K2Category', 'Table'); + $row->load($id); + $output .= ' +
    • + + '.$row->name.' + + +
    • + '; + } + $output .= '
    '; + return $output; + } + +} + +class JFormFieldCategoriesLatest extends K2ElementCategoriesLatest +{ + var $type = 'categorieslatest'; +} + +class JElementCategoriesLatest extends K2ElementCategoriesLatest +{ + var $_name = 'categorieslatest'; +} diff --git a/administrator/components/com_k2/elements/categoriesmultiple.php b/administrator/components/com_k2/elements/categoriesmultiple.php new file mode 100644 index 0000000..8122b77 --- /dev/null +++ b/administrator/components/com_k2/elements/categoriesmultiple.php @@ -0,0 +1,160 @@ +setQuery($query); + $mitems = $db->loadObjectList(); + $children = array(); + if ($mitems) + { + foreach ($mitems as $v) + { + if (K2_JVERSION != '15') + { + $v->title = $v->name; + $v->parent_id = $v->parent; + } + $pt = $v->parent; + $list = @$children[$pt] ? $children[$pt] : array(); + array_push($list, $v); + $children[$pt] = $list; + } + } + $list = JHTML::_('menu.treerecurse', 0, '', array(), $children, 9999, 0, 0); + $mitems = array(); + + foreach ($list as $item) + { + $item->treename = JString::str_ireplace(' ', '- ', $item->treename); + $mitems[] = JHTML::_('select.option', $item->id, ' '.$item->treename); + } + + $doc = JFactory::getDocument(); + if (K2_JVERSION != '15') + { + $js = " + \$K2(document).ready(function(){ + + \$K2('#jform_params_catfilter0').click(function(){ + \$K2('#jformparamscategory_id').attr('disabled', 'disabled'); + \$K2('#jformparamscategory_id option').each(function() { + \$K2(this).attr('selected', 'selected'); + }); + \$K2('#jformparamscategory_id').trigger('liszt:updated'); + }); + + \$K2('#jform_params_catfilter1').click(function(){ + \$K2('#jformparamscategory_id').removeAttr('disabled'); + \$K2('#jformparamscategory_id option').each(function() { + \$K2(this).removeAttr('selected'); + }); + \$K2('#jformparamscategory_id').trigger('liszt:updated'); + }); + + if (\$K2('#jform_params_catfilter0').attr('checked')) { + \$K2('#jformparamscategory_id').attr('disabled', 'disabled'); + \$K2('#jformparamscategory_id option').each(function() { + \$K2(this).attr('selected', 'selected'); + }); + \$K2('#jformparamscategory_id').trigger('liszt:updated'); + } + + if (\$K2('#jform_params_catfilter1').attr('checked')) { + \$K2('#jformparamscategory_id').removeAttr('disabled'); + \$K2('#jformparamscategory_id').trigger('liszt:updated'); + } + + }); + "; + + } + else + { + $js = " + \$K2(document).ready(function(){ + + \$K2('#paramscatfilter0').click(function(){ + \$K2('#paramscategory_id').attr('disabled', 'disabled'); + \$K2('#paramscategory_id option').each(function() { + \$K2(this).attr('selected', 'selected'); + }); + }); + + \$K2('#paramscatfilter1').click(function(){ + \$K2('#paramscategory_id').removeAttr('disabled'); + \$K2('#paramscategory_id option').each(function() { + \$K2(this).removeAttr('selected'); + }); + + }); + + if (\$K2('#paramscatfilter0').attr('checked')) { + \$K2('#paramscategory_id').attr('disabled', 'disabled'); + \$K2('#paramscategory_id option').each(function() { + \$K2(this).attr('selected', 'selected'); + }); + } + + if (\$K2('#paramscatfilter1').attr('checked')) { + \$K2('#paramscategory_id').removeAttr('disabled'); + } + + }); + "; + + } + + if (K2_JVERSION != '15') + { + $fieldName = $name.'[]'; + } + else + { + $fieldName = $control_name.'['.$name.'][]'; + } + + $doc->addScriptDeclaration($js); + $output = JHTML::_('select.genericlist', $mitems, $fieldName, 'class="inputbox" multiple="multiple" size="10"', 'value', 'text', $value); + return $output; + } + +} + +class JFormFieldCategoriesMultiple extends K2ElementCategoriesMultiple +{ + var $type = 'categoriesmultiple'; +} + +class JElementCategoriesMultiple extends K2ElementCategoriesMultiple +{ + var $_name = 'categoriesmultiple'; +} diff --git a/administrator/components/com_k2/elements/category.php b/administrator/components/com_k2/elements/category.php new file mode 100644 index 0000000..970aebd --- /dev/null +++ b/administrator/components/com_k2/elements/category.php @@ -0,0 +1,255 @@ +setQuery($query); + $mitems = $db->loadObjectList(); + $children = array(); + if ($mitems) + { + foreach ($mitems as $v) + { + if (K2_JVERSION != '15') + { + $v->title = $v->name; + $v->parent_id = $v->parent; + } + $pt = $v->parent; + $list = @$children[$pt] ? $children[$pt] : array(); + array_push($list, $v); + $children[$pt] = $list; + } + } + + $list = JHTML::_('menu.treerecurse', 0, '', array(), $children, 9999, 0, 0); + $mitems = array(); + $option = JRequest::getCmd('option'); + $prefix = ($option == 'com_joomfish') ? 'refField_' : ''; + if ($name == 'categories' || $name == 'jform[params][categories]') + { + $doc = JFactory::getDocument(); + $js = " + window.addEvent('domready', function(){ + setTask(); + }); + + function setTask() { + var counter=0; + $$('#".$prefix."paramscategories option').each(function(el) { + if (el.selected){ + value=el.value; + counter++; + } + }); + if (counter>1 || counter==0){ + $('urlparamsid').setProperty('value',''); + $('urlparamstask').setProperty('value',''); + $('".$prefix."paramssingleCatOrdering').setProperty('disabled', 'disabled'); + enableParams(); + } + if (counter==1){ + $('urlparamsid').setProperty('value',value); + $('urlparamstask').setProperty('value','category'); + $('".$prefix."paramssingleCatOrdering').removeProperty('disabled'); + disableParams(); + } + } + + function disableParams(){ + $('".$prefix."paramsnum_leading_items').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_leading_columns').setProperty('disabled','disabled'); + $('".$prefix."paramsleadingImgSize').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_primary_items').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_primary_columns').setProperty('disabled','disabled'); + $('".$prefix."paramsprimaryImgSize').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_secondary_items').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_secondary_columns').setProperty('disabled','disabled'); + $('".$prefix."paramssecondaryImgSize').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_links').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_links_columns').setProperty('disabled','disabled'); + $('".$prefix."paramslinksImgSize').setProperty('disabled','disabled'); + $('".$prefix."paramscatCatalogMode').setProperty('disabled','disabled'); + $('".$prefix."paramscatFeaturedItems').setProperty('disabled','disabled'); + $('".$prefix."paramscatOrdering').setProperty('disabled','disabled'); + $('".$prefix."paramscatPagination').setProperty('disabled','disabled'); + $('".$prefix."paramscatPaginationResults0').setProperty('disabled','disabled'); + $('".$prefix."paramscatPaginationResults1').setProperty('disabled','disabled'); + $('".$prefix."paramscatFeedLink0').setProperty('disabled','disabled'); + $('".$prefix."paramscatFeedLink1').setProperty('disabled','disabled'); + $('".$prefix."paramscatFeedIcon0').setProperty('disabled','disabled'); + $('".$prefix."paramscatFeedIcon1').setProperty('disabled','disabled'); + $('".$prefix."paramstheme').setProperty('disabled','disabled'); + } + + function enableParams(){ + $('".$prefix."paramsnum_leading_items').removeProperty('disabled'); + $('".$prefix."paramsnum_leading_columns').removeProperty('disabled'); + $('".$prefix."paramsleadingImgSize').removeProperty('disabled'); + $('".$prefix."paramsnum_primary_items').removeProperty('disabled'); + $('".$prefix."paramsnum_primary_columns').removeProperty('disabled'); + $('".$prefix."paramsprimaryImgSize').removeProperty('disabled'); + $('".$prefix."paramsnum_secondary_items').removeProperty('disabled'); + $('".$prefix."paramsnum_secondary_columns').removeProperty('disabled'); + $('".$prefix."paramssecondaryImgSize').removeProperty('disabled'); + $('".$prefix."paramsnum_links').removeProperty('disabled'); + $('".$prefix."paramsnum_links_columns').removeProperty('disabled'); + $('".$prefix."paramslinksImgSize').removeProperty('disabled'); + $('".$prefix."paramscatCatalogMode').removeProperty('disabled'); + $('".$prefix."paramscatFeaturedItems').removeProperty('disabled'); + $('".$prefix."paramscatOrdering').removeProperty('disabled'); + $('".$prefix."paramscatPagination').removeProperty('disabled'); + $('".$prefix."paramscatPaginationResults0').removeProperty('disabled'); + $('".$prefix."paramscatPaginationResults1').removeProperty('disabled'); + $('".$prefix."paramscatFeedLink0').removeProperty('disabled'); + $('".$prefix."paramscatFeedLink1').removeProperty('disabled'); + $('".$prefix."paramscatFeedIcon0').removeProperty('disabled'); + $('".$prefix."paramscatFeedIcon1').removeProperty('disabled'); + $('".$prefix."paramstheme').removeProperty('disabled'); + } + "; + + if (K2_JVERSION != '15') + { + $js = " + function disableParams(){ + $('jform_params_num_leading_items').setProperty('disabled','disabled'); + $('jform_params_num_leading_columns').setProperty('disabled','disabled'); + $('jform_params_leadingImgSize').setProperty('disabled','disabled'); + $('jform_params_num_primary_items').setProperty('disabled','disabled'); + $('jform_params_num_primary_columns').setProperty('disabled','disabled'); + $('jform_params_primaryImgSize').setProperty('disabled','disabled'); + $('jform_params_num_secondary_items').setProperty('disabled','disabled'); + $('jform_params_num_secondary_columns').setProperty('disabled','disabled'); + $('jform_params_secondaryImgSize').setProperty('disabled','disabled'); + $('jform_params_num_links').setProperty('disabled','disabled'); + $('jform_params_num_links_columns').setProperty('disabled','disabled'); + $('jform_params_linksImgSize').setProperty('disabled','disabled'); + $('jform_params_catCatalogMode').setProperty('disabled','disabled'); + $('jform_params_catFeaturedItems').setProperty('disabled','disabled'); + $('jform_params_catOrdering').setProperty('disabled','disabled'); + $('jform_params_catPagination').setProperty('disabled','disabled'); + $('jform_params_catPaginationResults0').setProperty('disabled','disabled'); + $('jform_params_catPaginationResults1').setProperty('disabled','disabled'); + $('jform_params_catFeedLink0').setProperty('disabled','disabled'); + $('jform_params_catFeedLink1').setProperty('disabled','disabled'); + $('jform_params_catFeedIcon0').setProperty('disabled','disabled'); + $('jform_params_catFeedIcon1').setProperty('disabled','disabled'); + $('jformparamstheme').setProperty('disabled','disabled'); + } + + function enableParams(){ + $('jform_params_num_leading_items').removeProperty('disabled'); + $('jform_params_num_leading_columns').removeProperty('disabled'); + $('jform_params_leadingImgSize').removeProperty('disabled'); + $('jform_params_num_primary_items').removeProperty('disabled'); + $('jform_params_num_primary_columns').removeProperty('disabled'); + $('jform_params_primaryImgSize').removeProperty('disabled'); + $('jform_params_num_secondary_items').removeProperty('disabled'); + $('jform_params_num_secondary_columns').removeProperty('disabled'); + $('jform_params_secondaryImgSize').removeProperty('disabled'); + $('jform_params_num_links').removeProperty('disabled'); + $('jform_params_num_links_columns').removeProperty('disabled'); + $('jform_params_linksImgSize').removeProperty('disabled'); + $('jform_params_catCatalogMode').removeProperty('disabled'); + $('jform_params_catFeaturedItems').removeProperty('disabled'); + $('jform_params_catOrdering').removeProperty('disabled'); + $('jform_params_catPagination').removeProperty('disabled'); + $('jform_params_catPaginationResults0').removeProperty('disabled'); + $('jform_params_catPaginationResults1').removeProperty('disabled'); + $('jform_params_catFeedLink0').removeProperty('disabled'); + $('jform_params_catFeedLink1').removeProperty('disabled'); + $('jform_params_catFeedIcon0').removeProperty('disabled'); + $('jform_params_catFeedIcon1').removeProperty('disabled'); + $('jformparamstheme').removeProperty('disabled'); + } + + function setTask() { + var counter=0; + $$('#jformparamscategories option').each(function(el) { + if (el.selected){ + value=el.value; + counter++; + } + }); + if (counter>1 || counter==0){ + $('jform_request_id').setProperty('value',''); + $('jform_request_task').setProperty('value',''); + $('jform_params_singleCatOrdering').setProperty('disabled', 'disabled'); + enableParams(); + } + if (counter==1){ + $('jform_request_id').setProperty('value',value); + $('jform_request_task').setProperty('value','category'); + $('jform_params_singleCatOrdering').removeProperty('disabled'); + disableParams(); + } + } + + window.addEvent('domready', function(){ + if($('request-options')) { + $$('.panel')[0].setStyle('display', 'none'); + } + setTask(); + }); + "; + } + + $doc->addScriptDeclaration($js); + } + + foreach ($list as $item) + { + $item->treename = JString::str_ireplace(' ', '- ', $item->treename); + @$mitems[] = JHTML::_('select.option', $item->id, $item->treename); + } + + if (K2_JVERSION != '15') + { + $fieldName = $name.'[]'; + } + else + { + $fieldName = $control_name.'['.$name.'][]'; + } + + if ($name == 'categories' || $name == 'jform[params][categories]') + { + $onChange = 'onchange="setTask();"'; + } + else + { + $onChange = ''; + } + + return JHTML::_('select.genericlist', $mitems, $fieldName, $onChange.' class="inputbox" style="width:90%;" multiple="multiple" size="15"', 'value', 'text', $value); + + } + +} + +class JFormFieldCategory extends K2ElementCategory +{ + var $type = 'category'; +} + +class JElementCategory extends K2ElementCategory +{ + var $_name = 'category'; +} diff --git a/administrator/components/com_k2/elements/header.php b/administrator/components/com_k2/elements/header.php new file mode 100644 index 0000000..8babfa2 --- /dev/null +++ b/administrator/components/com_k2/elements/header.php @@ -0,0 +1,47 @@ +addStyleSheet(JURI::root(true).'/media/k2/assets/css/k2.modules.css?v=2.6.7'); + if (K2_JVERSION == '15') + { + return '
    '.JText::_($value).'
    '; + } + else + { + return '
    '.JText::_($value).'
    '; + + } + } + + public function fetchTooltip($label, $description, &$node, $control_name, $name) + { + return NULL; + } + +} + +class JFormFieldHeader extends K2ElementHeader +{ + var $type = 'header'; +} + +class JElementHeader extends K2ElementHeader +{ + var $_name = 'header'; +} diff --git a/administrator/components/com_k2/elements/item.php b/administrator/components/com_k2/elements/item.php new file mode 100644 index 0000000..0c7c9ef --- /dev/null +++ b/administrator/components/com_k2/elements/item.php @@ -0,0 +1,85 @@ +load($value); + } + else + { + $item->title = JText::_('K2_SELECT_AN_ITEM'); + } + + $js = " + function jSelectItem(id, title, object) { + document.getElementById('".$name."' + '_id').value = id; + document.getElementById('".$name."' + '_name').value = title; + if(typeof(window.parent.SqueezeBox.close=='function')){ + window.parent.SqueezeBox.close(); + } + else { + document.getElementById('sbox-window').close(); + } + } + "; + $doc->addScriptDeclaration($js); + $link = 'index.php?option=com_k2&view=items&task=element&tmpl=component&object='.$name; + JHTML::_('behavior.modal', 'a.modal'); + if (K2_JVERSION == '30') + { + $html = ' + + '.JText::_('K2_SELECT').' + + '; + } + else + { + $html = ' +
    + +
    + + '; + } + + return $html; + } + +} + +class JFormFieldItem extends K2ElementItem +{ + var $type = 'item'; +} + +class JElementItem extends K2ElementItem +{ + var $_name = 'item'; +} diff --git a/administrator/components/com_k2/elements/itemform.php b/administrator/components/com_k2/elements/itemform.php new file mode 100644 index 0000000..7b9cac2 --- /dev/null +++ b/administrator/components/com_k2/elements/itemform.php @@ -0,0 +1,56 @@ +addScriptDeclaration(" + window.addEvent('domready', function() { + if($('request-options')) { + $$('.panel')[0].setStyle('display', 'none'); + } + if($('jform_browserNav')) { + $('jform_browserNav').setProperty('value', 2); + $('jform_browserNav').getElements('option')[0].destroy(); + } + if($('browserNav')) { + $('browserNav').setProperty('value', 2); + options = $('browserNav').getElements('option'); + if(options.length == 3) { + options[0].remove(); + } + } + }); + "); + return ''; + } + + function fetchTooltip($label, $description, &$node, $control_name, $name) + { + return ''; + } + +} + +class JFormFielditemform extends K2ElementItemForm +{ + var $type = 'itemform'; +} + +class JElementitemform extends K2ElementItemForm +{ + var $_name = 'itemform'; +} diff --git a/administrator/components/com_k2/elements/items.php b/administrator/components/com_k2/elements/items.php new file mode 100644 index 0000000..1b5d58a --- /dev/null +++ b/administrator/components/com_k2/elements/items.php @@ -0,0 +1,123 @@ +getAttribute('multiple') : $node->attributes()->multiple; + if (!$attribute) + { + $fieldName .= '[]'; + } + $image = JURI::root(true).'/administrator/templates/'.$mainframe->getTemplate().'/images/admin/publish_x.png'; + } + else + { + $fieldName = $control_name.'['.$name.'][]'; + $image = JURI::root(true).'/administrator/images/publish_x.png'; + } + + $js = " + function jSelectItem(id, title, object) { + var exists = false; + \$K2('#itemsList input').each(function(){ + if(\$K2(this).val()==id){ + alert('".JText::_('K2_THE_SELECTED_ITEM_IS_ALREADY_IN_THE_LIST')."'); + exists = true; + } + }); + if(!exists){ + var container = \$K2('
  • ').appendTo(\$K2('#itemsList')); + var img = \$K2('',{'class':'remove', src:'".$image."'}).appendTo(container); + img.click(function(){\$K2(this).parent().remove();}); + var span = \$K2('',{'class':'handle'}).html(title).appendTo(container); + var input = \$K2('',{value:id, type:'hidden', name:'".$fieldName."'}).appendTo(container); + var div = \$K2('
    ',{style:'clear:both;'}).appendTo(container); + \$K2('#itemsList').sortable('refresh'); + alert('".JText::_('K2_ITEM_ADDED_IN_THE_LIST', true)."'); + } + } + + \$K2(document).ready(function(){ + \$K2('#itemsList').sortable({ + containment: '#itemsList', + items: 'li', + handle: 'span.handle' + }); + \$K2('body').css('overflow-y', 'scroll'); + \$K2('#itemsList .remove').click(function(){ + \$K2(this).parent().remove(); + }); + }); + "; + + $document->addScriptDeclaration($js); + $document->addStyleSheet(JURI::root(true).'/media/k2/assets/css/k2.modules.css?v=2.6.7'); + + $current = array(); + if (is_string($value) && !empty($value)) + { + $current[] = $value; + } + if (is_array($value)) + { + $current = $value; + } + + JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_k2'.DS.'tables'); + $output = '
      '; + foreach ($current as $id) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($id); + $output .= ' +
    • + '.JText::_('K2_REMOVE_ENTRY_FROM_LIST').' + '.$row->title.' + + +
    • + '; + } + $output .= '
    '; + return $output; + } + +} + +class JFormFieldItems extends K2ElementItems +{ + var $type = 'items'; +} + +class JElementItems extends K2ElementItems +{ + var $_name = 'items'; +} diff --git a/administrator/components/com_k2/elements/k2category.php b/administrator/components/com_k2/elements/k2category.php new file mode 100644 index 0000000..e935d36 --- /dev/null +++ b/administrator/components/com_k2/elements/k2category.php @@ -0,0 +1,255 @@ +setQuery($query); + $mitems = $db->loadObjectList(); + $children = array(); + if ($mitems) + { + foreach ($mitems as $v) + { + if (K2_JVERSION != '15') + { + $v->title = $v->name; + $v->parent_id = $v->parent; + } + $pt = $v->parent; + $list = @$children[$pt] ? $children[$pt] : array(); + array_push($list, $v); + $children[$pt] = $list; + } + } + + $list = JHTML::_('menu.treerecurse', 0, '', array(), $children, 9999, 0, 0); + $mitems = array(); + $option = JRequest::getCmd('option'); + $prefix = ($option == 'com_joomfish') ? 'refField_' : ''; + if ($name == 'categories' || $name == 'jform[params][categories]') + { + $doc = JFactory::getDocument(); + $js = " + window.addEvent('domready', function(){ + setTask(); + }); + + function setTask() { + var counter=0; + $$('#".$prefix."paramscategories option').each(function(el) { + if (el.selected){ + value=el.value; + counter++; + } + }); + if (counter>1 || counter==0){ + $('urlparamsid').setProperty('value',''); + $('urlparamstask').setProperty('value',''); + $('".$prefix."paramssingleCatOrdering').setProperty('disabled', 'disabled'); + enableParams(); + } + if (counter==1){ + $('urlparamsid').setProperty('value',value); + $('urlparamstask').setProperty('value','category'); + $('".$prefix."paramssingleCatOrdering').removeProperty('disabled'); + disableParams(); + } + } + + function disableParams(){ + $('".$prefix."paramsnum_leading_items').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_leading_columns').setProperty('disabled','disabled'); + $('".$prefix."paramsleadingImgSize').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_primary_items').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_primary_columns').setProperty('disabled','disabled'); + $('".$prefix."paramsprimaryImgSize').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_secondary_items').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_secondary_columns').setProperty('disabled','disabled'); + $('".$prefix."paramssecondaryImgSize').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_links').setProperty('disabled','disabled'); + $('".$prefix."paramsnum_links_columns').setProperty('disabled','disabled'); + $('".$prefix."paramslinksImgSize').setProperty('disabled','disabled'); + $('".$prefix."paramscatCatalogMode').setProperty('disabled','disabled'); + $('".$prefix."paramscatFeaturedItems').setProperty('disabled','disabled'); + $('".$prefix."paramscatOrdering').setProperty('disabled','disabled'); + $('".$prefix."paramscatPagination').setProperty('disabled','disabled'); + $('".$prefix."paramscatPaginationResults0').setProperty('disabled','disabled'); + $('".$prefix."paramscatPaginationResults1').setProperty('disabled','disabled'); + $('".$prefix."paramscatFeedLink0').setProperty('disabled','disabled'); + $('".$prefix."paramscatFeedLink1').setProperty('disabled','disabled'); + $('".$prefix."paramscatFeedIcon0').setProperty('disabled','disabled'); + $('".$prefix."paramscatFeedIcon1').setProperty('disabled','disabled'); + $('".$prefix."paramstheme').setProperty('disabled','disabled'); + } + + function enableParams(){ + $('".$prefix."paramsnum_leading_items').removeProperty('disabled'); + $('".$prefix."paramsnum_leading_columns').removeProperty('disabled'); + $('".$prefix."paramsleadingImgSize').removeProperty('disabled'); + $('".$prefix."paramsnum_primary_items').removeProperty('disabled'); + $('".$prefix."paramsnum_primary_columns').removeProperty('disabled'); + $('".$prefix."paramsprimaryImgSize').removeProperty('disabled'); + $('".$prefix."paramsnum_secondary_items').removeProperty('disabled'); + $('".$prefix."paramsnum_secondary_columns').removeProperty('disabled'); + $('".$prefix."paramssecondaryImgSize').removeProperty('disabled'); + $('".$prefix."paramsnum_links').removeProperty('disabled'); + $('".$prefix."paramsnum_links_columns').removeProperty('disabled'); + $('".$prefix."paramslinksImgSize').removeProperty('disabled'); + $('".$prefix."paramscatCatalogMode').removeProperty('disabled'); + $('".$prefix."paramscatFeaturedItems').removeProperty('disabled'); + $('".$prefix."paramscatOrdering').removeProperty('disabled'); + $('".$prefix."paramscatPagination').removeProperty('disabled'); + $('".$prefix."paramscatPaginationResults0').removeProperty('disabled'); + $('".$prefix."paramscatPaginationResults1').removeProperty('disabled'); + $('".$prefix."paramscatFeedLink0').removeProperty('disabled'); + $('".$prefix."paramscatFeedLink1').removeProperty('disabled'); + $('".$prefix."paramscatFeedIcon0').removeProperty('disabled'); + $('".$prefix."paramscatFeedIcon1').removeProperty('disabled'); + $('".$prefix."paramstheme').removeProperty('disabled'); + } + "; + + if (K2_JVERSION != '15') + { + $js = " + function disableParams(){ + $('jform_params_num_leading_items').setProperty('disabled','disabled'); + $('jform_params_num_leading_columns').setProperty('disabled','disabled'); + $('jform_params_leadingImgSize').setProperty('disabled','disabled'); + $('jform_params_num_primary_items').setProperty('disabled','disabled'); + $('jform_params_num_primary_columns').setProperty('disabled','disabled'); + $('jform_params_primaryImgSize').setProperty('disabled','disabled'); + $('jform_params_num_secondary_items').setProperty('disabled','disabled'); + $('jform_params_num_secondary_columns').setProperty('disabled','disabled'); + $('jform_params_secondaryImgSize').setProperty('disabled','disabled'); + $('jform_params_num_links').setProperty('disabled','disabled'); + $('jform_params_num_links_columns').setProperty('disabled','disabled'); + $('jform_params_linksImgSize').setProperty('disabled','disabled'); + $('jform_params_catCatalogMode').setProperty('disabled','disabled'); + $('jform_params_catFeaturedItems').setProperty('disabled','disabled'); + $('jform_params_catOrdering').setProperty('disabled','disabled'); + $('jform_params_catPagination').setProperty('disabled','disabled'); + $('jform_params_catPaginationResults0').setProperty('disabled','disabled'); + $('jform_params_catPaginationResults1').setProperty('disabled','disabled'); + $('jform_params_catFeedLink0').setProperty('disabled','disabled'); + $('jform_params_catFeedLink1').setProperty('disabled','disabled'); + $('jform_params_catFeedIcon0').setProperty('disabled','disabled'); + $('jform_params_catFeedIcon1').setProperty('disabled','disabled'); + $('jformparamstheme').setProperty('disabled','disabled'); + } + + function enableParams(){ + $('jform_params_num_leading_items').removeProperty('disabled'); + $('jform_params_num_leading_columns').removeProperty('disabled'); + $('jform_params_leadingImgSize').removeProperty('disabled'); + $('jform_params_num_primary_items').removeProperty('disabled'); + $('jform_params_num_primary_columns').removeProperty('disabled'); + $('jform_params_primaryImgSize').removeProperty('disabled'); + $('jform_params_num_secondary_items').removeProperty('disabled'); + $('jform_params_num_secondary_columns').removeProperty('disabled'); + $('jform_params_secondaryImgSize').removeProperty('disabled'); + $('jform_params_num_links').removeProperty('disabled'); + $('jform_params_num_links_columns').removeProperty('disabled'); + $('jform_params_linksImgSize').removeProperty('disabled'); + $('jform_params_catCatalogMode').removeProperty('disabled'); + $('jform_params_catFeaturedItems').removeProperty('disabled'); + $('jform_params_catOrdering').removeProperty('disabled'); + $('jform_params_catPagination').removeProperty('disabled'); + $('jform_params_catPaginationResults0').removeProperty('disabled'); + $('jform_params_catPaginationResults1').removeProperty('disabled'); + $('jform_params_catFeedLink0').removeProperty('disabled'); + $('jform_params_catFeedLink1').removeProperty('disabled'); + $('jform_params_catFeedIcon0').removeProperty('disabled'); + $('jform_params_catFeedIcon1').removeProperty('disabled'); + $('jformparamstheme').removeProperty('disabled'); + } + + function setTask() { + var counter=0; + $$('#jformparamscategories option').each(function(el) { + if (el.selected){ + value=el.value; + counter++; + } + }); + if (counter>1 || counter==0){ + $('jform_request_id').setProperty('value',''); + $('jform_request_task').setProperty('value',''); + $('jform_params_singleCatOrdering').setProperty('disabled', 'disabled'); + enableParams(); + } + if (counter==1){ + $('jform_request_id').setProperty('value',value); + $('jform_request_task').setProperty('value','category'); + $('jform_params_singleCatOrdering').removeProperty('disabled'); + disableParams(); + } + } + + window.addEvent('domready', function(){ + if($('request-options')) { + $$('.panel')[0].setStyle('display', 'none'); + } + setTask(); + }); + "; + } + + $doc->addScriptDeclaration($js); + } + + foreach ($list as $item) + { + $item->treename = JString::str_ireplace(' ', '- ', $item->treename); + @$mitems[] = JHTML::_('select.option', $item->id, $item->treename); + } + + if (K2_JVERSION != '15') + { + $fieldName = $name.'[]'; + } + else + { + $fieldName = $control_name.'['.$name.'][]'; + } + + if ($name == 'categories' || $name == 'jform[params][categories]') + { + $onChange = 'onchange="setTask();"'; + } + else + { + $onChange = ''; + } + + return JHTML::_('select.genericlist', $mitems, $fieldName, $onChange.' class="inputbox" multiple="multiple" size="15"', 'value', 'text', $value); + + } + +} + +class JFormFieldK2Category extends K2ElementK2Category +{ + var $type = 'k2category'; +} + +class JElementK2Category extends K2ElementK2Category +{ + var $_name = 'k2category'; +} diff --git a/administrator/components/com_k2/elements/k2tag.php b/administrator/components/com_k2/elements/k2tag.php new file mode 100644 index 0000000..3891531 --- /dev/null +++ b/administrator/components/com_k2/elements/k2tag.php @@ -0,0 +1,89 @@ +Quote($value); + $db->setQuery($query); + $tag = $db->loadObject(); + } + if (is_null($tag)) + { + $tag = new stdClass; + $tag->name = JText::_('K2_SELECT_A_TAG'); + } + // Move this to main JS file + $js = " + function jSelectTag(id, title, object) { + document.getElementById('".$name."' + '_id').value = id; + document.getElementById('".$name."' + '_name').value = title; + if(typeof(window.parent.SqueezeBox.close=='function')){ + window.parent.SqueezeBox.close(); + } + else { + document.getElementById('sbox-window').close(); + } + } + "; + $doc->addScriptDeclaration($js); + $link = 'index.php?option=com_k2&view=tags&task=element&tmpl=component&object='.$name; + JHTML::_('behavior.modal', 'a.modal'); + if (K2_JVERSION == '30') + { + $html = ' + + '.JText::_('K2_SELECT').' + + '; + } + else + { + $html = ' +
    + +
    + + + '; + } + return $html; + } + +} + +class JFormFieldK2Tag extends K2ElementK2Tag +{ + var $type = 'k2tag'; +} + +class JElementK2Tag extends K2ElementK2Tag +{ + var $_name = 'k2tag'; +} diff --git a/administrator/components/com_k2/elements/k2user.php b/administrator/components/com_k2/elements/k2user.php new file mode 100644 index 0000000..ef811e7 --- /dev/null +++ b/administrator/components/com_k2/elements/k2user.php @@ -0,0 +1,84 @@ +name = JText::_('K2_SELECT_A_USER'); + } + // Move this to main JS file + $js = " + function jSelectUser(id, title, object) { + document.getElementById('".$name."' + '_id').value = id; + document.getElementById('".$name."' + '_name').value = title; + if(typeof(window.parent.SqueezeBox.close=='function')){ + window.parent.SqueezeBox.close(); + } + else { + document.getElementById('sbox-window').close(); + } + } + "; + $doc->addScriptDeclaration($js); + $link = 'index.php?option=com_k2&view=users&task=element&tmpl=component&object='.$name; + JHTML::_('behavior.modal', 'a.modal'); + if (K2_JVERSION == '30') + { + $html = ' + + '.JText::_('K2_SELECT').' + + '; + } + else + { + $html = ' +
    + +
    + + + '; + } + return $html; + } + +} + +class JFormFieldK2User extends K2ElementK2User +{ + var $type = 'k2user'; +} + +class JElementK2User extends K2ElementK2User +{ + var $_name = 'k2user'; +} diff --git a/administrator/components/com_k2/elements/menuitem.php b/administrator/components/com_k2/elements/menuitem.php new file mode 100644 index 0000000..5523969 --- /dev/null +++ b/administrator/components/com_k2/elements/menuitem.php @@ -0,0 +1,152 @@ +setQuery($query); + $menuTypes = $db->loadObjectList(); + + $where = ''; + if ($state = $node->attributes('state')) + { + $where .= ' AND published = '.(int)$state; + } + + // load the list of menu items + // TODO: move query to model + if (K2_JVERSION != '15') + { + $query = 'SELECT id, parent_id, title, menutype, type, published'.' FROM #__menu'.$where.' ORDER BY menutype, parent_id, ordering'; + } + else + { + $query = 'SELECT id, parent, name, menutype, type, published'.' FROM #__menu'.$where.' ORDER BY menutype, parent, ordering'; + + } + + $db->setQuery($query); + $menuItems = $db->loadObjectList(); + + // establish the hierarchy of the menu + // TODO: use node model + $children = array(); + + if ($menuItems) + { + // first pass - collect children + foreach ($menuItems as $v) + { + if (K2_JVERSION != '15') + { + $v->parent = $v->parent_id; + $v->name = $v->title; + } + $pt = $v->parent; + $list = @$children[$pt] ? $children[$pt] : array(); + array_push($list, $v); + $children[$pt] = $list; + } + } + + // second pass - get an indent list of the items + $list = JHTML::_('menu.treerecurse', 0, '', array(), $children, 9999, 0, 0); + + foreach ($list as $item) + { + $item->treename = JString::str_ireplace(' ', ' -', $item->treename); + $mitems[] = JHTML::_('select.option', $item->id, ' '.$item->treename); + } + + // assemble into menutype groups + $n = count($list); + $groupedList = array(); + foreach ($list as $k => $v) + { + $groupedList[$v->menutype][] = &$list[$k]; + } + + // assemble menu items to the array + $options = array(); + $options[] = JHTML::_('select.option', '', '- '.JText::_('K2_SELECT_MENU_ITEM').' -'); + + foreach ($menuTypes as $type) + { + if ($type != '') + { + $options[] = JHTML::_('select.option', '0', ' ', 'value', 'text', true); + $options[] = JHTML::_('select.option', $type->menutype, $type->title.' - '.JText::_('K2_TOP'), 'value', 'text', true); + } + if (isset($groupedList[$type->menutype])) + { + $n = count($groupedList[$type->menutype]); + for ($i = 0; $i < $n; $i++) + { + $item = &$groupedList[$type->menutype][$i]; + + //If menutype is changed but item is not saved yet, use the new type in the list + if (JRequest::getString('option', '', 'get') == 'com_menus') + { + $currentItemArray = JRequest::getVar('cid', array(0), '', 'array'); + $currentItemId = (int)$currentItemArray[0]; + $currentItemType = JRequest::getString('type', $item->type, 'get'); + if ($currentItemId == $item->id && $currentItemType != $item->type) + { + $item->type = $currentItemType; + } + } + + $disable = @strpos($node->attributes('disable'), $item->type) !== false ? true : false; + + if ($item->published == 0) + $item->treename .= ' [**'.JText::_('K2_UNPUBLISHED').'**]'; + if ($item->published == -2) + $item->treename .= ' [**'.JText::_('K2_TRASHED').'**]'; + + $options[] = JHTML::_('select.option', $item->id, $item->treename, 'value', 'text', $disable); + + } + } + } + + if (K2_JVERSION != '15') + { + $fieldName = $name; + } + else + { + $fieldName = $control_name.'['.$name.']'; + } + + return JHTML::_('select.genericlist', $options, $fieldName, 'class="inputbox"', 'value', 'text', $value, $control_name.$name); + } + +} + +class JFormFieldMenuItem extends K2ElementMenuItem +{ + var $type = 'MenuItem'; +} + +class JElementMenuItem extends K2ElementMenuItem +{ + var $_name = 'MenuItem'; +} diff --git a/administrator/components/com_k2/elements/menus.php b/administrator/components/com_k2/elements/menus.php new file mode 100644 index 0000000..af88be5 --- /dev/null +++ b/administrator/components/com_k2/elements/menus.php @@ -0,0 +1,44 @@ +setQuery($query); + $menus = $db->loadObjectList(); + $options = array(); + $options[] = JHTML::_('select.option', '', JText::_('K2_NONE_ONSELECTLISTS')); + foreach ($menus as $menu) + { + $options[] = JHTML::_('select.option', $menu->menutype, $menu->title); + } + return JHTML::_('select.genericlist', $options, $fieldName, 'class="inputbox"', 'value', 'text', $value); + } + +} + +class JFormFieldMenus extends K2ElementMenus +{ + var $type = 'menus'; +} + +class JElementMenus extends K2ElementMenus +{ + var $_name = 'menus'; +} diff --git a/administrator/components/com_k2/elements/moduletemplate.php b/administrator/components/com_k2/elements/moduletemplate.php new file mode 100644 index 0000000..7881134 --- /dev/null +++ b/administrator/components/com_k2/elements/moduletemplate.php @@ -0,0 +1,93 @@ +attributes()->modulename; + } + else + { + $moduleName = $node->_attributes['modulename']; + } + $moduleTemplatesPath = JPATH_SITE.DS.'modules'.DS.$moduleName.DS.'tmpl'; + $moduleTemplatesFolders = JFolder::folders($moduleTemplatesPath); + + $db = JFactory::getDBO(); + if (K2_JVERSION != '15') + { + $query = "SELECT template FROM #__template_styles WHERE client_id = 0 AND home = 1"; + } + else + { + $query = "SELECT template FROM #__templates_menu WHERE client_id = 0 AND menuid = 0"; + } + $db->setQuery($query); + $defaultemplate = $db->loadResult(); + $templatePath = JPATH_SITE.DS.'templates'.DS.$defaultemplate.DS.'html'.DS.$moduleName; + + if (JFolder::exists($templatePath)) + { + $templateFolders = JFolder::folders($templatePath); + $folders = @array_merge($templateFolders, $moduleTemplatesFolders); + $folders = @array_unique($folders); + } + else + { + $folders = $moduleTemplatesFolders; + } + + $exclude = 'Default'; + $options = array(); + + foreach ($folders as $folder) + { + if (preg_match(chr(1).$exclude.chr(1), $folder)) + { + continue; + } + $options[] = JHTML::_('select.option', $folder, $folder); + } + + array_unshift($options, JHTML::_('select.option', 'Default', '-- '.JText::_('K2_USE_DEFAULT').' --')); + + if (K2_JVERSION != '15') + { + $fieldName = $name; + } + else + { + $fieldName = $control_name.'['.$name.']'; + } + + return JHTML::_('select.genericlist', $options, $fieldName, 'class="inputbox"', 'value', 'text', $value, $control_name.$name); + + } + +} + +class JFormFieldModuleTemplate extends K2ElementModuleTemplate +{ + var $type = 'moduletemplate'; +} + +class JElementModuleTemplate extends K2ElementModuleTemplate +{ + var $_name = 'moduletemplate'; +} diff --git a/administrator/components/com_k2/elements/template.php b/administrator/components/com_k2/elements/template.php new file mode 100644 index 0000000..6e53c0d --- /dev/null +++ b/administrator/components/com_k2/elements/template.php @@ -0,0 +1,85 @@ +setQuery($query); + $defaultemplate = $db->loadResult(); + + if (JFolder::exists(JPATH_SITE.DS.'templates'.DS.$defaultemplate.DS.'html'.DS.'com_k2'.DS.'templates')) + { + $templatePath = JPATH_SITE.DS.'templates'.DS.$defaultemplate.DS.'html'.DS.'com_k2'.DS.'templates'; + } + else + { + $templatePath = JPATH_SITE.DS.'templates'.DS.$defaultemplate.DS.'html'.DS.'com_k2'; + } + + if (JFolder::exists($templatePath)) + { + $templateFolders = JFolder::folders($templatePath); + $folders = @array_merge($templateFolders, $componentFolders); + $folders = @array_unique($folders); + } + else + { + $folders = $componentFolders; + } + + $exclude = 'default'; + $options = array(); + foreach ($folders as $folder) + { + if (preg_match(chr(1).$exclude.chr(1), $folder)) + { + continue; + } + $options[] = JHTML::_('select.option', $folder, $folder); + } + + array_unshift($options, JHTML::_('select.option', '', '-- '.JText::_('K2_USE_DEFAULT').' --')); + + return JHTML::_('select.genericlist', $options, $fieldName, 'class="inputbox"', 'value', 'text', $value, $control_name.$name); + + } + +} + +class JFormFieldTemplate extends K2ElementTemplate +{ + var $type = 'template'; +} + +class JElementTemplate extends K2ElementTemplate +{ + var $_name = 'template'; +} diff --git a/administrator/components/com_k2/elements/user.php b/administrator/components/com_k2/elements/user.php new file mode 100644 index 0000000..83f8ae0 --- /dev/null +++ b/administrator/components/com_k2/elements/user.php @@ -0,0 +1,84 @@ +name = JText::_('K2_SELECT_A_USER'); + } + // Move this to main JS file + $js = " + function jSelectUser(id, title, object) { + document.getElementById('".$name."' + '_id').value = id; + document.getElementById('".$name."' + '_name').value = title; + if(typeof(window.parent.SqueezeBox.close=='function')){ + window.parent.SqueezeBox.close(); + } + else { + document.getElementById('sbox-window').close(); + } + } + "; + $doc->addScriptDeclaration($js); + $link = 'index.php?option=com_k2&view=users&task=element&tmpl=component&object='.$name; + JHTML::_('behavior.modal', 'a.modal'); + if (K2_JVERSION == '30') + { + $html = ' + + '.JText::_('K2_SELECT').' + + '; + } + else + { + $html = ' +
    + +
    + + + '; + } + return $html; + } + +} + +class JFormFieldUser extends K2ElementUser +{ + var $type = 'k2user'; +} + +class JElementHeader extends K2ElementUser +{ + var $_name = 'k2user'; +} diff --git a/administrator/components/com_k2/elements/users.php b/administrator/components/com_k2/elements/users.php new file mode 100644 index 0000000..ced725e --- /dev/null +++ b/administrator/components/com_k2/elements/users.php @@ -0,0 +1,122 @@ +attributes('multiple')) + { + $fieldName .= '[]'; + } + $image = JURI::root(true).'/administrator/templates/'.$mainframe->getTemplate().'/images/admin/publish_x.png'; + } + else + { + $fieldName = $control_name.'['.$name.'][]'; + $image = JURI::root(true).'/administrator/images/publish_x.png'; + } + + $js = " + function jSelectUser(id, title, object) { + var exists = false; + \$K2('#usersList input').each(function(){ + if(\$K2(this).val()==id){ + alert('".JText::_('K2_THE_SELECTED_USER_IS_ALREADY_IN_THE_LIST', true)."'); + exists = true; + } + }); + if(!exists){ + var container = \$K2('
  • ').appendTo(\$K2('#usersList')); + var img = \$K2('',{'class':'remove', src:'".$image."'}).appendTo(container); + img.click(function(){\$K2(this).parent().remove();}); + var span = \$K2('',{'class':'handle'}).html(title).appendTo(container); + var input = \$K2('',{value:id, type:'hidden', name:'".$fieldName."'}).appendTo(container); + var div = \$K2('
    ',{style:'clear:both;'}).appendTo(container); + \$K2('#usersList').sortable('refresh'); + alert('".JText::_('K2_USER_ADDED_IN_THE_LIST', true)."'); + } + } + + \$K2(document).ready(function(){ + \$K2('#usersList').sortable({ + containment: '#usersList', + items: 'li', + handle: 'span.handle' + }); + \$K2('body').css('overflow-y', 'scroll'); + \$K2('#usersList .remove').click(function(){ + \$K2(this).parent().remove(); + }); + }); + "; + + $document->addScriptDeclaration($js); + $document->addStyleSheet(JURI::root(true).'/media/k2/assets/css/k2.modules.css?v=2.6.7'); + + $current = array(); + if (is_string($value) && !empty($value)) + { + $current[] = $value; + } + if (is_array($value)) + { + $current = $value; + } + + $output = '
      '; + foreach ($current as $id) + { + $row = JFactory::getUser($id); + $output .= ' +
    • + '.JText::_('K2_REMOVE_ENTRY_FROM_LIST').' + '.$row->name.' + +
      +
    • + '; + } + $output .= '
    '; + return $output; + } + +} + +class JFormFieldUsers extends K2ElementUsers +{ + var $type = 'users'; +} + +class JElementUsers extends K2ElementUsers +{ + var $_name = 'users'; +} diff --git a/administrator/components/com_k2/elements/userslatest.php b/administrator/components/com_k2/elements/userslatest.php new file mode 100644 index 0000000..e0dfbb4 --- /dev/null +++ b/administrator/components/com_k2/elements/userslatest.php @@ -0,0 +1,133 @@ +attributes('multiple')) + { + $fieldName .= '[]'; + } + $image = JURI::root(true).'/administrator/templates/'.$mainframe->getTemplate().'/images/admin/publish_x.png'; + } + else + { + $fieldName = $control_name.'['.$name.'][]'; + $image = JURI::root(true).'/administrator/images/publish_x.png'; + } + + $js = " + function jSelectUser(id, title, object) { + var exists = false; + \$K2('#usersList input').each(function(){ + if(\$K2(this).val()==id){ + alert('".JText::_('K2_THE_SELECTED_USER_IS_ALREADY_IN_THE_LIST', true)."'); + exists = true; + } + }); + if(!exists){ + var container = \$K2('
  • ').appendTo(\$K2('#usersList')); + var img = \$K2('',{'class':'remove', src:'".$image."'}).appendTo(container); + img.click(function(){\$K2(this).parent().remove();}); + var span = \$K2('',{'class':'handle'}).html(title).appendTo(container); + var input = \$K2('',{value:id, type:'hidden', name:'".$fieldName."'}).appendTo(container); + var div = \$K2('
    ',{style:'clear:both;'}).appendTo(container); + \$K2('#usersList').sortable('refresh'); + alert('".JText::_('K2_USER_ADDED_IN_THE_LIST', true)."'); + } + } + + \$K2(document).ready(function(){ + \$K2('#usersList').sortable({ + containment: '#usersList', + items: 'li', + handle: 'span.handle' + }); + \$K2('body').css('overflow-y', 'scroll'); + \$K2('#usersList .remove').click(function(){ + \$K2(this).parent().remove(); + }); + }); + "; + + $document->addScriptDeclaration($js); + $document->addStyleSheet(JURI::root(true).'/media/k2/assets/css/k2.modules.css?v=2.6.7'); + + $current = array(); + if (is_string($value) && !empty($value)) + { + $current[] = $value; + } + if (is_array($value)) + { + $current = $value; + } + + $output = ' + +
    + '; + + $output .= '
      '; + foreach ($current as $id) + { + $row = JFactory::getUser($id); + $output .= ' +
    • + '.JText::_('K2_REMOVE_ENTRY_FROM_LIST').' + '.$row->name.' + + +
    • + '; + } + $output .= '
    '; + return $output; + } + +} + +class JFormFieldUsersLatest extends K2ElementUsersLatest +{ + var $type = 'userslatest'; +} + +class JElementUsersLatest extends K2ElementUsersLatest +{ + var $_name = 'userslatest'; +} diff --git a/administrator/components/com_k2/helpers/html.php b/administrator/components/com_k2/helpers/html.php new file mode 100644 index 0000000..6a508fd --- /dev/null +++ b/administrator/components/com_k2/helpers/html.php @@ -0,0 +1,132 @@ +get('lockTags') || $user->gid > 23) + { + JSubMenuHelper::addEntry(JText::_('K2_TAGS'), 'index.php?option=com_k2&view=tags', $view == 'tags'); + } + JSubMenuHelper::addEntry(JText::_('K2_COMMENTS'), 'index.php?option=com_k2&view=comments', $view == 'comments'); + if ($user->gid > 23) + { + JSubMenuHelper::addEntry(JText::_('K2_USERS'), 'index.php?option=com_k2&view=users', $view == 'users'); + JSubMenuHelper::addEntry(JText::_('K2_USER_GROUPS'), 'index.php?option=com_k2&view=usergroups', $view == 'usergroups'); + JSubMenuHelper::addEntry(JText::_('K2_EXTRA_FIELDS'), 'index.php?option=com_k2&view=extrafields', $view == 'extrafields'); + JSubMenuHelper::addEntry(JText::_('K2_EXTRA_FIELD_GROUPS'), 'index.php?option=com_k2&view=extrafieldsgroups', $view == 'extrafieldsgroups'); + } + JSubMenuHelper::addEntry(JText::_('K2_MEDIA_MANAGER'), 'index.php?option=com_k2&view=media', $view == 'media'); + JSubMenuHelper::addEntry(JText::_('K2_INFORMATION'), 'index.php?option=com_k2&view=info', $view == 'info'); + } + + public static function stateToggler(&$row, $key, $property = 'published', $tasks = array('publish', 'unpublish'), $labels = array('K2_PUBLISH', 'K2_UNPUBLISH')) + { + $task = $row->$property ? $tasks[1] : $tasks[0]; + $action = $row->$property ? JText::_($labels[1]) : JText::_($labels[0]); + $class = 'k2Toggler'; + $status = $row->$property ? 'k2Active' : 'k2Inactive'; + $href = ''.$action.''; + return $href; + } + + public static function loadjQuery($ui = false, $mediaManager = false) + { + JLoader::register('K2HelperUtilities', JPATH_SITE.DS.'components'.DS.'com_k2'.DS.'helpers'.DS.'utilities.php'); + + $application = JFactory::getApplication(); + $document = JFactory::getDocument(); + $params = K2HelperUtilities::getParams('com_k2'); + + if ($document->getType() == 'html') + { + + if (K2_JVERSION == '15') + { + JHtml::_('behavior.mootools'); + } + else if (K2_JVERSION == '25') + { + JHtml::_('behavior.framework'); + } + else + { + JHtml::_('behavior.framework'); + if ($application->isAdmin() || ($application->isSite() && $params->get('jQueryHandling'))) + { + JHtml::_('jquery.framework'); + } + } + + $handling = $application->isAdmin() ? $params->get('backendJQueryHandling', 'remote') : $params->get('jQueryHandling', '1.8remote'); + // jQuery + if (K2_JVERSION != '30') + { + if ($handling == 'remote') + { + $document->addScript('//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js'); + } + else if ($handling == 'local') + { + $document->addScript(JURI::root(true).'/media/k2/assets/js/jquery-1.8.3.min.js'); + } + else + { + if ($handling && JString::strpos($handling, 'remote') !== false) + { + if ($handling == '1.9remote') + { + $handling = '1remote'; + } + $document->addScript('//ajax.googleapis.com/ajax/libs/jquery/'.str_replace('remote', '', $handling).'/jquery.min.js'); + } + else if ($handling && JString::strpos($handling, 'remote') === false) + { + $document->addScript(JURI::root(true).'/media/k2/assets/js/jquery-'.$handling.'.min.js'); + } + } + } + + // jQuery UI + if ($application->isAdmin() || $ui) + { + + // No conflict loaded when $ui requested or in the backend. + // No need to reload for $mediaManager as the latter is always called with $ui + $document->addScript(JURI::root(true).'/media/k2/assets/js/k2.noconflict.js'); + + if ($handling == 'local') + { + $document->addScript(JURI::root(true).'/media/k2/assets/js/jquery-ui-1.8.24.custom.min.js'); + } + else + { + $document->addScript('//ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js'); + } + } + + if ($mediaManager) + { + $document->addScript(JURI::root(true).'/media/k2/assets/js/elfinder.min.js?v=2.6.7'); + } + } + } + +} diff --git a/administrator/components/com_k2/install.mysql.sql b/administrator/components/com_k2/install.mysql.sql new file mode 100644 index 0000000..b6b3ee3 --- /dev/null +++ b/administrator/components/com_k2/install.mysql.sql @@ -0,0 +1,174 @@ +CREATE TABLE IF NOT EXISTS `#__k2_attachments` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `itemID` int(11) NOT NULL, + `filename` varchar(255) NOT NULL, + `title` varchar(255) NOT NULL, + `titleAttribute` text NOT NULL, + `hits` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `itemID` (`itemID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__k2_categories` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `alias` varchar(255) NOT NULL, + `description` text NOT NULL, + `parent` int(11) DEFAULT '0', + `extraFieldsGroup` int(11) NOT NULL, + `published` smallint(6) NOT NULL DEFAULT '0', + `access` int(11) NOT NULL DEFAULT '0', + `ordering` int(11) NOT NULL DEFAULT '0', + `image` varchar(255) NOT NULL, + `params` text NOT NULL, + `trash` smallint(6) NOT NULL DEFAULT '0', + `plugins` text NOT NULL, + `language` char(7) NOT NULL, + PRIMARY KEY (`id`), + KEY `category` (`published`,`access`,`trash`), + KEY `parent` (`parent`), + KEY `ordering` (`ordering`), + KEY `published` (`published`), + KEY `access` (`access`), + KEY `trash` (`trash`), + KEY `language` (`language`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__k2_comments` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `itemID` int(11) NOT NULL, + `userID` int(11) NOT NULL, + `userName` varchar(255) NOT NULL, + `commentDate` datetime NOT NULL, + `commentText` text NOT NULL, + `commentEmail` varchar(255) NOT NULL, + `commentURL` varchar(255) NOT NULL, + `published` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `itemID` (`itemID`), + KEY `userID` (`userID`), + KEY `published` (`published`), + KEY `latestComments` (`published`,`commentDate`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__k2_extra_fields` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `value` text NOT NULL, + `type` varchar(255) NOT NULL, + `group` int(11) NOT NULL, + `published` tinyint(4) NOT NULL, + `ordering` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `group` (`group`), + KEY `published` (`published`), + KEY `ordering` (`ordering`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__k2_extra_fields_groups` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__k2_items` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `title` varchar(255) NOT NULL, + `alias` varchar(255) DEFAULT NULL, + `catid` int(11) NOT NULL, + `published` smallint(6) NOT NULL DEFAULT '0', + `introtext` mediumtext NOT NULL, + `fulltext` mediumtext NOT NULL, + `video` text, + `gallery` varchar(255) DEFAULT NULL, + `extra_fields` text CHARACTER SET utf8 COLLATE utf8_unicode_ci, + `extra_fields_search` text NOT NULL, + `created` datetime NOT NULL, + `created_by` int(11) NOT NULL DEFAULT '0', + `created_by_alias` varchar(255) NOT NULL, + `checked_out` int(10) unsigned NOT NULL, + `checked_out_time` datetime NOT NULL, + `modified` datetime NOT NULL, + `modified_by` int(11) NOT NULL DEFAULT '0', + `publish_up` datetime NOT NULL, + `publish_down` datetime NOT NULL, + `trash` smallint(6) NOT NULL DEFAULT '0', + `access` int(11) NOT NULL DEFAULT '0', + `ordering` int(11) NOT NULL DEFAULT '0', + `featured` smallint(6) NOT NULL DEFAULT '0', + `featured_ordering` int(11) NOT NULL DEFAULT '0', + `image_caption` text NOT NULL, + `image_credits` varchar(255) NOT NULL, + `video_caption` text NOT NULL, + `video_credits` varchar(255) NOT NULL, + `hits` int(10) unsigned NOT NULL, + `params` text NOT NULL, + `metadesc` text NOT NULL, + `metadata` text NOT NULL, + `metakey` text NOT NULL, + `plugins` text NOT NULL, + `language` char(7) NOT NULL, + PRIMARY KEY (`id`), + KEY `item` (`published`,`publish_up`,`publish_down`,`trash`,`access`), + KEY `catid` (`catid`), + KEY `created_by` (`created_by`), + KEY `ordering` (`ordering`), + KEY `featured` (`featured`), + KEY `featured_ordering` (`featured_ordering`), + KEY `hits` (`hits`), + KEY `created` (`created`), + KEY `language` (`language`), + FULLTEXT KEY `search` (`title`,`introtext`,`fulltext`,`extra_fields_search`,`image_caption`,`image_credits`,`video_caption`,`video_credits`,`metadesc`,`metakey`), + FULLTEXT KEY `title` (`title`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__k2_rating` ( + `itemID` int(11) NOT NULL DEFAULT '0', + `rating_sum` int(11) unsigned NOT NULL DEFAULT '0', + `rating_count` int(11) unsigned NOT NULL DEFAULT '0', + `lastip` varchar(50) NOT NULL DEFAULT '', + PRIMARY KEY (`itemID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__k2_tags` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `published` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `published` (`published`), + FULLTEXT KEY `name` (`name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__k2_tags_xref` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `tagID` int(11) NOT NULL, + `itemID` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `tagID` (`tagID`), + KEY `itemID` (`itemID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__k2_users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `userID` int(11) NOT NULL, + `userName` varchar(255) DEFAULT NULL, + `gender` enum('m','f') NOT NULL DEFAULT 'm', + `description` text NOT NULL, + `image` varchar(255) DEFAULT NULL, + `url` varchar(255) DEFAULT NULL, + `group` int(11) NOT NULL DEFAULT '0', + `plugins` text NOT NULL, + `ip` varchar(15) NOT NULL, + `hostname` varchar(255) NOT NULL, + `notes` text NOT NULL, + PRIMARY KEY (`id`), + KEY `userID` (`userID`), + KEY `group` (`group`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `#__k2_user_groups` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `permissions` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; \ No newline at end of file diff --git a/administrator/components/com_k2/jupgrade/j16upgrade.php b/administrator/components/com_k2/jupgrade/j16upgrade.php new file mode 100644 index 0000000..039b673 --- /dev/null +++ b/administrator/components/com_k2/jupgrade/j16upgrade.php @@ -0,0 +1,92 @@ + + * + * + * administrator/components/com_k2/jupgrade/j16upgrade.php + * jUpgradeComponentK2 + * + * + * For more information, see ./j16upgrade.xml + */ +class jUpgradeComponentK2 extends jUpgrade +{ + /** + * Check if K2 migration is supported. + */ + protected function detectExtension() + { + return true; + } + + /** + * Migrate custom information. + * + * This function gets called after all folders and tables have been copied. + * + * If you want to split this task into smaller chunks, + * please store your custom state variables into $this->state and return false. + * Returning false will force jUpgrade to call this function again, + * which allows you to continue import by reading $this->state before continuing. + * + * @return boolean Ready (true/false) + * @since 1.6.4 + * @throws Exception + */ + protected function migrateExtensionCustom() + { + return true; + } + + protected function copyTable_k2_categories($table) { + $this->source = $this->destination = "#__{$table}"; + + // Clone table + $this->cloneTable($this->source, $this->destination); + + // Get data + $rows = parent::getSourceData('*'); + + // Do some custom post processing on the list. + foreach ($rows as &$row) { + $row['access'] = $row['access'] == 0 ? 1 : $row['access'] + 1; + $row['params'] = $this->convertParams($row['params']); + } + $this->setDestinationData($rows); + return true; + } + + protected function copyTable_k2_items($table) { + $this->source = $this->destination = "#__{$table}"; + + // Clone table + $this->cloneTable($this->source, $this->destination); + + // Get data + $rows = parent::getSourceData('*'); + + // Do some custom post processing on the list. + foreach ($rows as &$row) { + $row['access'] = $row['access'] == 0 ? 1 : $row['access'] + 1; + $row['params'] = $this->convertParams($row['params']); + $row['plugins'] = $this->convertParams($row['plugins']); + } + $this->setDestinationData($rows); + return true; + } + +} diff --git a/administrator/components/com_k2/jupgrade/j16upgrade.xml b/administrator/components/com_k2/jupgrade/j16upgrade.xml new file mode 100644 index 0000000..e22ef3d --- /dev/null +++ b/administrator/components/com_k2/jupgrade/j16upgrade.xml @@ -0,0 +1,49 @@ + + + + http://getk2.org/collection.xml + + administrator/components/com_k2/jupgrade/j16upgrade.php + jUpgradeComponentK2 + + + + k2_attachments
    + k2_categories
    + k2_comments
    + k2_extra_fields
    + k2_extra_fields_groups
    + k2_items
    + k2_rating
    + k2_tags
    + k2_tags_xref
    + k2_users
    + k2_user_groups
    +
    + + + administrator/components/com_k2 + components/com_k2 + media/k2 + + + + mod_k2_comments + + + mod_k2_content + + + mod_k2_login + + + mod_k2_tools + + + mod_k2_user + + + mod_k2_users + + +
    \ No newline at end of file diff --git a/administrator/components/com_k2/jupgrade/j25upgrade.php b/administrator/components/com_k2/jupgrade/j25upgrade.php new file mode 100644 index 0000000..9be1f46 --- /dev/null +++ b/administrator/components/com_k2/jupgrade/j25upgrade.php @@ -0,0 +1,92 @@ + + * + * + * administrator/components/com_k2/jupgrade/j16upgrade.php + * jUpgradeComponentK2 + * + * + * For more information, see ./j16upgrade.xml + */ +class jUpgradeComponentK2 extends jUpgradeExtensions +{ + /** + * Check if K2 migration is supported. + */ + protected function detectExtension() + { + return true; + } + + /** + * Migrate custom information. + * + * This function gets called after all folders and tables have been copied. + * + * If you want to split this task into smaller chunks, + * please store your custom state variables into $this->state and return false. + * Returning false will force jUpgrade to call this function again, + * which allows you to continue import by reading $this->state before continuing. + * + * @return boolean Ready (true/false) + * @since 1.6.4 + * @throws Exception + */ + protected function migrateExtensionCustom() + { + return true; + } + + protected function copyTable_k2_categories($table) { + $this->source = $this->destination = "#__{$table}"; + + // Clone table + $this->cloneTable($this->source, $this->destination); + + // Get data + $rows = parent::getSourceData('*'); + + // Do some custom post processing on the list. + foreach ($rows as &$row) { + $row['access'] = $row['access'] == 0 ? 1 : $row['access'] + 1; + $row['params'] = $this->convertParams($row['params']); + } + $this->setDestinationData($rows); + return true; + } + + protected function copyTable_k2_items($table) { + $this->source = $this->destination = "#__{$table}"; + + // Clone table + $this->cloneTable($this->source, $this->destination); + + // Get data + $rows = parent::getSourceData('*'); + + // Do some custom post processing on the list. + foreach ($rows as &$row) { + $row['access'] = $row['access'] == 0 ? 1 : $row['access'] + 1; + $row['params'] = $this->convertParams($row['params']); + $row['plugins'] = $this->convertParams($row['plugins']); + } + $this->setDestinationData($rows); + return true; + } + +} diff --git a/administrator/components/com_k2/jupgrade/j25upgrade.xml b/administrator/components/com_k2/jupgrade/j25upgrade.xml new file mode 100644 index 0000000..4a3f3fe --- /dev/null +++ b/administrator/components/com_k2/jupgrade/j25upgrade.xml @@ -0,0 +1,49 @@ + + + + http://getk2.org/collection.xml + + administrator/components/com_k2/jupgrade/j25upgrade.php + jUpgradeComponentK2 + + + + k2_attachments
    + k2_categories
    + k2_comments
    + k2_extra_fields
    + k2_extra_fields_groups
    + k2_items
    + k2_rating
    + k2_tags
    + k2_tags_xref
    + k2_users
    + k2_user_groups
    +
    + + + administrator/components/com_k2 + components/com_k2 + media/k2 + + + + mod_k2_comments + + + mod_k2_content + + + mod_k2_login + + + mod_k2_tools + + + mod_k2_user + + + mod_k2_users + + +
    \ No newline at end of file diff --git a/administrator/components/com_k2/k2.php b/administrator/components/com_k2/k2.php new file mode 100644 index 0000000..8acb9f5 --- /dev/null +++ b/administrator/components/com_k2/k2.php @@ -0,0 +1,143 @@ +get('lockTags') && $user->gid<=23 && ($view=='tags' || $view=='tag')) || ($user->gid <= 23) && ( + $view=='extrafield' || + $view=='extrafields' || + $view=='extrafieldsgroup' || + $view=='extrafieldsgroups' || + $view=='user' || + ($view=='users' && $task != 'element') || + $view=='usergroup' || + $view=='usergroups' + ) + ) + { + JError::raiseError( 403, JText::_('K2_ALERTNOTAUTH') ); + } +} +else { + + JLoader::register('K2HelperPermissions', JPATH_SITE.DS.'components'.DS.'com_k2'.DS.'helpers'.DS.'permissions.j16.php'); + K2HelperPermissions::checkPermissions(); + + // Compatibility for gid variable + if($user->authorise('core.admin', 'com_k2')){ + $user->gid = 1000; + } + else { + $user->gid = 1; + } + + if( ($params->get('lockTags') && !$user->authorise('core.admin', 'com_k2') && ($view=='tags' || $view=='tag')) || + (!$user->authorise('core.admin', 'com_k2')) && ( + $view=='extrafield' || + $view=='extrafields' || + $view=='extrafieldsgroup' || + $view=='extrafieldsgroups' || + $view=='user' || + ($view=='users' && $task != 'element') || + $view=='usergroup' || + $view=='usergroups' + ) + ) + { + JError::raiseError( 403, JText::_('K2_ALERTNOTAUTH') ); + } +} + +$document = JFactory::getDocument(); + +if(version_compare(JVERSION,'1.6.0','ge')) { + JHtml::_('behavior.framework'); +} else { + JHTML::_('behavior.mootools'); +} + +// CSS +$document->addStyleSheet(JURI::root(true).'/media/k2/assets/css/k2.css?v=2.6.7'); + +K2HelperHTML::loadjQuery(true, JRequest::getCmd('view') == 'media'); + +// JS +if(K2_JVERSION == '30') +{ + JHtml::_('formbehavior.chosen', 'select'); +} +$document->addScriptDeclaration('K2JVersion = "'.K2_JVERSION.'";'); +$document->addScript(JURI::root(true).'/media/k2/assets/js/k2.js?v=2.6.7&sitepath='.JURI::root(true).'/'); + +// Container CSS class definition +if(K2_JVERSION == '15'){ + $k2CSSContainerClass = ' isJ15'; +} elseif(K2_JVERSION == '25'){ + $k2CSSContainerClass = ' isJ25'; +} elseif(K2_JVERSION == '30'){ + $k2CSSContainerClass = ' isJ25 isJ30'; +} else { + $k2CSSContainerClass = ''; +} + +if( $document->getType() != 'raw' && JRequest::getWord('task')!='deleteAttachment' && JRequest::getWord('task')!='connector' && JRequest::getWord('task')!='tag' && JRequest::getWord('task')!='extrafields' && JRequest::getWord('task')!='download' && JRequest::getWord('task')!='saveComment'): ?> + +
    +registerTask('saveAndNew', 'save'); +$controller->execute(JRequest::getWord('task')); +$controller->redirect(); + +if( $document->getType() != 'raw' && JRequest::getWord('task')!='deleteAttachment' && JRequest::getWord('task')!='connector' && JRequest::getWord('task')!='tag' && JRequest::getWord('task')!='extrafields' && JRequest::getWord('task')!='download' && JRequest::getWord('task')!='saveComment'): ?> +
    +
    + K2 v2.6.7 | Copyright © 2006- JoomlaWorks Ltd. +
    + + + COM_K2 + JoomlaWorks + July 8th, 2013 + Copyright (c) 2006 - 2013 JoomlaWorks Ltd. All rights reserved. + please-use-the-contact-form@joomlaworks.net + www.joomlaworks.net + 2.6.7 + http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL + Thank you for installing K2 by JoomlaWorks, the powerful content extension for Joomla! + install.k2.php + uninstall.k2.php + script.k2.php + + + install.mysql.sql + install.mysql.sql + + + + + uninstall.mysql.sql + uninstall.mysql.sql + + + + http://getk2.org/update.xml + + + controllers + css + helpers + images + js + models + sef_ext + templates + views + k2.php + router.php + + + assets + attachments + categories + galleries + items + users + videos + + + en-GB.com_k2.ini + en-GB.mod_k2_comments.ini + en-GB.mod_k2_comments.sys.ini + en-GB.mod_k2_content.ini + en-GB.mod_k2_content.sys.ini + en-GB.mod_k2_tools.ini + en-GB.mod_k2_tools.sys.ini + en-GB.mod_k2_users.ini + en-GB.mod_k2_users.sys.ini + en-GB.mod_k2_user.ini + en-GB.mod_k2_user.sys.ini + + + COM_K2 + + K2_ITEMS + K2_CATEGORIES + K2_TAGS + K2_COMMENTS + K2_USERS + K2_USER_GROUPS + K2_EXTRA_FIELDS + K2_EXTRA_FIELD_GROUPS + K2_MEDIA_MANAGER + K2_INFORMATION + + + controllers + elements + helpers + jupgrade + lib + models + tables + views + access.xml + k2.php + config.xml + install.mysql.sql + uninstall.mysql.sql + + + en-GB.com_k2.ini + en-GB.com_k2.menu.ini + en-GB.com_k2.j16.ini + en-GB.mod_k2_quickicons.ini + en-GB.mod_k2_quickicons.sys.ini + en-GB.mod_k2_stats.ini + en-GB.mod_k2_stats.sys.ini + en-GB.mod_k2.j16.ini + en-GB.plg_finder_k2.ini + en-GB.plg_finder_k2.sys.ini + en-GB.plg_search_k2.ini + en-GB.plg_search_k2.sys.ini + en-GB.plg_system_k2.ini + en-GB.plg_system_k2.sys.ini + en-GB.plg_user_k2.ini + en-GB.plg_user_k2.sys.ini + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + k2_attachments.xml + k2_categories.xml + k2_extra_fields.xml + k2_items.xml + k2_tags.xml + k2_users.xml + +
    diff --git a/administrator/components/com_k2/lib/JSON.php b/administrator/components/com_k2/lib/JSON.php new file mode 100644 index 0000000..74c8dcd --- /dev/null +++ b/administrator/components/com_k2/lib/JSON.php @@ -0,0 +1,815 @@ + + * @author Matt Knapp + * @author Brett Stimmerman + * @copyright 2005 Michal Migurski + * @version CVS: $Id: JSON.php 1812 2013-01-14 18:45:06Z lefteris.kavadas $ + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +if(!defined('SERVICES_JSON_SLICE')) define('SERVICES_JSON_SLICE', 1); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +if(!defined('SERVICES_JSON_IN_STR')) define('SERVICES_JSON_IN_STR', 2); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +if(!defined('SERVICES_JSON_IN_ARR')) define('SERVICES_JSON_IN_ARR', 3); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +if(!defined('SERVICES_JSON_IN_OBJ')) define('SERVICES_JSON_IN_OBJ', 4); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +if(!defined('SERVICES_JSON_IN_CMT')) define('SERVICES_JSON_IN_CMT', 5); + +/** + * Behavior switch for Services_JSON::decode() + */ +if(!defined('SERVICES_JSON_LOOSE_TYPE')) define('SERVICES_JSON_LOOSE_TYPE', 16); + +/** + * Behavior switch for Services_JSON::decode() + */ +if(!defined('SERVICES_JSON_SUPPRESS_ERRORS')) define('SERVICES_JSON_SUPPRESS_ERRORS', 32); + +/** + * Converts to and from JSON format. + * + * Brief example of use: + * + * + * // create a new instance of Services_JSON + * $json = new Services_JSON(); + * + * // convert a complexe value to JSON notation, and send it to the browser + * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); + * $output = $json->encode($value); + * + * print($output); + * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] + * + * // accept incoming POST data, assumed to be in JSON notation + * $input = file_get_contents('php://input', 1000000); + * $value = $json->decode($input); + * + */ +if(!class_exists('Services_JSON')){ + class Services_JSON + { + /** + * constructs a new JSON instance + * + * @param int $use object behavior flags; combine with boolean-OR + * + * possible values: + * - SERVICES_JSON_LOOSE_TYPE: loose typing. + * "{...}" syntax creates associative arrays + * instead of objects in decode(). + * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. + * Values which can't be encoded (e.g. resources) + * appear as NULL instead of throwing errors. + * By default, a deeply-nested resource will + * bubble up with an error, so all return values + * from encode() should be checked with isError() + */ + function Services_JSON($use = 0) + { + $this->use = $use; + } + + /** + * convert a string from one UTF-16 char to one UTF-8 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf16 UTF-16 character + * @return string UTF-8 character + * @access private + */ + function utf162utf8($utf16) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + } + + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch(true) { + case ((0x7F & $bytes) == $bytes): + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) + . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) + . chr(0x80 | (($bytes >> 6) & 0x3F)) + . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + function utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + function encode($var) + { + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + $properties = array_map(array($this, 'name_value'), + array_keys($var), + array_values($var)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + } + + // treat it like a regular array + $elements = array_map(array($this, 'encode'), $var); + + foreach($elements as $element) { + if(Services_JSON::isError($element)) { + return $element; + } + } + + return '[' . join(',', $elements) . ']'; + + case 'object': + $vars = get_object_vars($var); + + $properties = array_map(array($this, 'name_value'), + array_keys($vars), + array_values($vars)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + + default: + return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) + ? 'null' + : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + function name_value($name, $value) + { + $encoded_value = $this->encode($value); + + if(Services_JSON::isError($encoded_value)) { + return $encoded_value; + } + + return $this->encode(strval($name)) . ':' . $encoded_value; + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to Services_JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) { + case 'true': + return true; + + case 'false': + return false; + + case 'null': + return null; + + default: + $m = array(); + + if (is_numeric($str)) { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) + ? (integer)$str + : (float)$str; + + } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = substr($str, 0, 1); + $chrs = substr($str, 1, -1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = substr($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { + $utf8 .= $chrs{++$c}; + } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) + . chr(hexdec(substr($chrs, ($c + 4), 2))); + $utf8 .= $this->utf162utf8($utf16); + $c += 5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 6); + $c += 5; + break; + + } + + } + + return $utf8; + + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { + // array, or object notation + + if ($str{0} == '[') { + $stk = array(SERVICES_JSON_IN_ARR); + $arr = array(); + } else { + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = array(); + } else { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => SERVICES_JSON_SLICE, + 'where' => 0, + 'delim' => false)); + + $chrs = substr($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') { + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } else { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = substr($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = substr($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + $parts = array(); + + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } + + } + + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { + // found a quote, and we are not inside a string + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); + + } elseif (($chrs{$c} == $top['delim']) && + ($top['what'] == SERVICES_JSON_IN_STR) && + ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) { + // found a quote, we're in a string, and it's not escaped + // we know that it's not escaped becase there is _not_ an + // odd number of backslashes at the end of the string so far + array_pop($stk); + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '[') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); + + } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '{') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); + + } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($substr_chrs_c_2 == '/*') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); + + } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { + // found a comment end, and we're in one now + array_pop($stk); + $c++; + + for ($i = $top['where']; $i <= $c; ++$i) + $chrs = substr_replace($chrs, ' ', $i, 1); + + //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + + } + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + return $obj; + + } + + } + } + } + + /** + * @todo Ultimately, this should just call PEAR::isError() + */ + function isError($data, $code = null) + { + if (class_exists('pear')) { + return PEAR::isError($data, $code); + } elseif (is_object($data) && (get_class($data) == 'services_json_error' || + is_subclass_of($data, 'services_json_error'))) { + return true; + } + + return false; + } + } +} + +if (!class_exists('Services_JSON_Error')) { + if (class_exists('PEAR_Error')) { + class Services_JSON_Error extends PEAR_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + parent::PEAR_Error($message, $code, $mode, $options, $userinfo); + } + } + } else { + /** + * @todo Ultimately, this class shall be descended from PEAR_Error + */ + class Services_JSON_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + + } + } + } +} diff --git a/administrator/components/com_k2/lib/akismet.class.php b/administrator/components/com_k2/lib/akismet.class.php new file mode 100644 index 0000000..f4bf25b --- /dev/null +++ b/administrator/components/com_k2/lib/akismet.class.php @@ -0,0 +1,536 @@ + + * $akismet = new Akismet('http://www.example.com/blog/', 'aoeu1aoue'); + * $akismet->setCommentAuthor($name); + * $akismet->setCommentAuthorEmail($email); + * $akismet->setCommentAuthorURL($url); + * $akismet->setCommentContent($comment); + * $akismet->setPermalink('http://www.example.com/blog/alex/someurl/'); + * + * if($akismet->isCommentSpam()) + * // store the comment but mark it as spam (in case of a mis-diagnosis) + * else + * // store the comment normally + * + * + * Optionally you may wish to check if your WordPress API key is valid as in the example below. + * + * + * $akismet = new Akismet('http://www.example.com/blog/', 'aoeu1aoue'); + * + * if($akismet->isKeyValid()) { + * // api key is okay + * } else { + * // api key is invalid + * } + * + * + * @package akismet + * @name Akismet + * @version 0.5 + * @author Alex Potsides + * @link http://www.achingbrain.net/ + */ +class Akismet +{ + private $version = '0.5'; + private $wordPressAPIKey; + private $blogURL; + private $comment; + private $apiPort; + private $akismetServer; + private $akismetVersion; + private $requestFactory; + + // This prevents some potentially sensitive information from being sent accross the wire. + private $ignore = array( + 'HTTP_COOKIE', + 'HTTP_X_FORWARDED_FOR', + 'HTTP_X_FORWARDED_HOST', + 'HTTP_MAX_FORWARDS', + 'HTTP_X_FORWARDED_SERVER', + 'REDIRECT_STATUS', + 'SERVER_PORT', + 'PATH', + 'DOCUMENT_ROOT', + 'SERVER_ADMIN', + 'QUERY_STRING', + 'PHP_SELF' + ); + + /** + * @param string $blogURL The URL of your blog. + * @param string $wordPressAPIKey WordPress API key. + */ + public function __construct($blogURL, $wordPressAPIKey) + { + $this->blogURL = $blogURL; + $this->wordPressAPIKey = $wordPressAPIKey; + + // Set some default values + $this->apiPort = 80; + $this->akismetServer = 'rest.akismet.com'; + $this->akismetVersion = '1.1'; + $this->requestFactory = new SocketWriteReadFactory(); + + // Start to populate the comment data + $this->comment['blog'] = $blogURL; + + if (isset($_SERVER['HTTP_USER_AGENT'])) + { + $this->comment['user_agent'] = $_SERVER['HTTP_USER_AGENT']; + } + + if (isset($_SERVER['HTTP_REFERER'])) + { + $this->comment['referrer'] = $_SERVER['HTTP_REFERER']; + } + + /* + * This is necessary if the server PHP5 is running on has been set up to run PHP4 and + * PHP5 concurently and is actually running through a separate proxy al a these instructions: + * http://www.schlitt.info/applications/blog/archives/83_How_to_run_PHP4_and_PHP_5_parallel.html + * and http://wiki.coggeshall.org/37.html + * Otherwise the user_ip appears as the IP address of the PHP4 server passing the requests to the + * PHP5 one... + */ + if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] != getenv('SERVER_ADDR')) + { + $this->comment['user_ip'] = $_SERVER['REMOTE_ADDR']; + } + else + { + $this->comment['user_ip'] = getenv('HTTP_X_FORWARDED_FOR'); + } + } + + /** + * Makes a request to the Akismet service to see if the API key passed to the constructor is valid. + * + * Use this method if you suspect your API key is invalid. + * + * @return bool True is if the key is valid, false if not. + */ + public function isKeyValid() + { + // Check to see if the key is valid + $response = $this->sendRequest('key='.$this->wordPressAPIKey.'&blog='.$this->blogURL, $this->akismetServer, '/'.$this->akismetVersion.'/verify-key'); + return $response[1] == 'valid'; + } + + // makes a request to the Akismet service + private function sendRequest($request, $host, $path) + { + $http_request = "POST ".$path." HTTP/1.0\r\n"; + $http_request .= "Host: ".$host."\r\n"; + $http_request .= "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n"; + $http_request .= "Content-Length: ".strlen($request)."\r\n"; + $http_request .= "User-Agent: Akismet PHP5 Class ".$this->version." | Akismet/1.11\r\n"; + $http_request .= "\r\n"; + $http_request .= $request; + + $requestSender = $this->requestFactory->createRequestSender(); + $response = $requestSender->send($host, $this->apiPort, $http_request); + + return explode("\r\n\r\n", $response, 2); + } + + // Formats the data for transmission + private function getQueryString() + { + foreach ($_SERVER as $key => $value) + { + if (!in_array($key, $this->ignore)) + { + if ($key == 'REMOTE_ADDR') + { + $this->comment[$key] = $this->comment['user_ip']; + } + else + { + $this->comment[$key] = $value; + } + } + } + + $query_string = ''; + + foreach ($this->comment as $key => $data) + { + if (!is_array($data)) + { + $query_string .= $key.'='.urlencode(stripslashes($data)).'&'; + } + } + + return $query_string; + } + + /** + * Tests for spam. + * + * Uses the web service provided by {@link http://www.akismet.com Akismet} to see whether or not the submitted comment is spam. Returns a boolean value. + * + * @return bool True if the comment is spam, false if not + * @throws Will throw an exception if the API key passed to the constructor is invalid. + */ + public function isCommentSpam() + { + $response = $this->sendRequest($this->getQueryString(), $this->wordPressAPIKey.'.rest.akismet.com', '/'.$this->akismetVersion.'/comment-check'); + + if ($response[1] == 'invalid' && !$this->isKeyValid()) + { + throw new exception('The Wordpress API key passed to the Akismet constructor is invalid. Please obtain a valid one from http://wordpress.com/api-keys/'); + } + + return ($response[1] == 'true'); + } + + /** + * Submit spam that is incorrectly tagged as ham. + * + * Using this function will make you a good citizen as it helps Akismet to learn from its mistakes. This will improve the service for everybody. + */ + public function submitSpam() + { + $this->sendRequest($this->getQueryString(), $this->wordPressAPIKey.'.'.$this->akismetServer, '/'.$this->akismetVersion.'/submit-spam'); + } + + /** + * Submit ham that is incorrectly tagged as spam. + * + * Using this function will make you a good citizen as it helps Akismet to learn from its mistakes. This will improve the service for everybody. + */ + public function submitHam() + { + $this->sendRequest($this->getQueryString(), $this->wordPressAPIKey.'.'.$this->akismetServer, '/'.$this->akismetVersion.'/submit-ham'); + } + + /** + * To override the user IP address when submitting spam/ham later on + * + * @param string $userip An IP address. Optional. + */ + public function setUserIP($userip) + { + $this->comment['user_ip'] = $userip; + } + + /** + * To override the referring page when submitting spam/ham later on + * + * @param string $referrer The referring page. Optional. + */ + public function setReferrer($referrer) + { + $this->comment['referrer'] = $referrer; + } + + /** + * A permanent URL referencing the blog post the comment was submitted to. + * + * @param string $permalink The URL. Optional. + */ + public function setPermalink($permalink) + { + $this->comment['permalink'] = $permalink; + } + + /** + * The type of comment being submitted. + * + * May be blank, comment, trackback, pingback, or a made up value like "registration" or "wiki". + */ + public function setCommentType($commentType) + { + $this->comment['comment_type'] = $commentType; + } + + /** + * The name that the author submitted with the comment. + */ + public function setCommentAuthor($commentAuthor) + { + $this->comment['comment_author'] = $commentAuthor; + } + + /** + * The email address that the author submitted with the comment. + * + * The address is assumed to be valid. + */ + public function setCommentAuthorEmail($authorEmail) + { + $this->comment['comment_author_email'] = $authorEmail; + } + + /** + * The URL that the author submitted with the comment. + */ + public function setCommentAuthorURL($authorURL) + { + $this->comment['comment_author_url'] = $authorURL; + } + + /** + * The comment's body text. + */ + public function setCommentContent($commentBody) + { + $this->comment['comment_content'] = $commentBody; + } + + /** + * Lets you override the user agent used to submit the comment. + * you may wish to do this when submitting ham/spam. + * Defaults to $_SERVER['HTTP_USER_AGENT'] + */ + public function setCommentUserAgent($userAgent) + { + $this->comment['user_agent'] = $userAgent; + } + + /** + * Defaults to 80 + */ + public function setAPIPort($apiPort) + { + $this->apiPort = $apiPort; + } + + /** + * Defaults to rest.akismet.com + */ + public function setAkismetServer($akismetServer) + { + $this->akismetServer = $akismetServer; + } + + /** + * Defaults to '1.1' + * + * @param string $akismetVersion + */ + public function setAkismetVersion($akismetVersion) + { + $this->akismetVersion = $akismetVersion; + } + + /** + * Used by unit tests to mock transport layer + * + * @param AkismetRequestFactory $requestFactory + */ + public function setRequestFactory($requestFactory) + { + $this->requestFactory = $requestFactory; + } + +} + +/** + * Used internally by Akismet + * + * This class is used by Akismet to do the actual sending and receiving of data. It opens a connection to a remote host, sends some data and the reads the response and makes it available to the calling program. + * + * The code that makes up this class originates in the Akismet WordPress plugin, which is {@link http://akismet.com/download/ available on the Akismet website}. + * + * N.B. It is not necessary to call this class directly to use the Akismet class. + * + * @package akismet + * @name SocketWriteRead + * @version 0.5 + * @author Alex Potsides + * @link http://www.achingbrain.net/ + */ +class SocketWriteRead implements AkismetRequestSender +{ + private $response; + private $errorNumber; + private $errorString; + + public function __construct() + { + $this->errorNumber = 0; + $this->errorString = ''; + } + + /** + * Sends the data to the remote host. + * + * @param string $host The host to send/receive data. + * @param int $port The port on the remote host. + * @param string $request The data to send. + * @param int $responseLength The amount of data to read. Defaults to 1160 bytes. + * @throws An exception is thrown if a connection cannot be made to the remote host. + * @returns The server response + */ + public function send($host, $port, $request, $responseLength = 1160) + { + $response = ''; + + $fs = fsockopen($host, $port, $this->errorNumber, $this->errorString, 3); + + if ($this->errorNumber != 0) + { + throw new Exception('Error connecting to host: '.$host.' Error number: '.$this->errorNumber.' Error message: '.$this->errorString); + } + + if ($fs !== false) + { + @fwrite($fs, $request); + + while (!feof($fs)) + { + $response .= fgets($fs, $responseLength); + } + + fclose($fs); + } + + return $response; + } + + /** + * Returns the server response text + * + * @return string + */ + public function getResponse() + { + return $this->response; + } + + /** + * Returns the error number + * + * If there was no error, 0 will be returned. + * + * @return int + */ + public function getErrorNumner() + { + return $this->errorNumber; + } + + /** + * Returns the error string + * + * If there was no error, an empty string will be returned. + * + * @return string + */ + public function getErrorString() + { + return $this->errorString; + } + +} + +/** + * Used internally by the Akismet class and to mock the Akismet anti spam service in + * the unit tests. + * + * N.B. It is not necessary to call this class directly to use the Akismet class. + * + * @package akismet + * @name SocketWriteReadFactory + * @version 0.5 + * @author Alex Potsides + * @link http://www.achingbrain.net/ + */ +class SocketWriteReadFactory implements AkismetRequestFactory +{ + + public function createRequestSender() + { + return new SocketWriteRead(); + } + +} + +/** + * Used internally by the Akismet class and to mock the Akismet anti spam service in + * the unit tests. + * + * N.B. It is not necessary to implement this class to use the Akismet class. + * + * @package akismet + * @name AkismetRequestSender + * @version 0.5 + * @author Alex Potsides + * @link http://www.achingbrain.net/ + */ +interface AkismetRequestSender +{ + + /** + * Sends the data to the remote host. + * + * @param string $host The host to send/receive data. + * @param int $port The port on the remote host. + * @param string $request The data to send. + * @param int $responseLength The amount of data to read. Defaults to 1160 bytes. + * @throws An exception is thrown if a connection cannot be made to the remote host. + * @returns The server response + */ + public function send($host, $port, $request, $responseLength = 1160); +} + +/** + * Used internally by the Akismet class and to mock the Akismet anti spam service in + * the unit tests. + * + * N.B. It is not necessary to implement this class to use the Akismet class. + * + * @package akismet + * @name AkismetRequestFactory + * @version 0.5 + * @author Alex Potsides + * @link http://www.achingbrain.net/ + */ +interface AkismetRequestFactory +{ + + public function createRequestSender(); +} diff --git a/administrator/components/com_k2/lib/class.upload.php b/administrator/components/com_k2/lib/class.upload.php new file mode 100644 index 0000000..5f5857f --- /dev/null +++ b/administrator/components/com_k2/lib/class.upload.php @@ -0,0 +1,5308 @@ + + * @license http://opensource.org/licenses/gpl-license.php GNU Public License + * @copyright Colin Verot + * @package cmf + * @subpackage external + */ + +/** + * Class upload + * + * What does it do? + * + * It manages file uploads for you. In short, it manages the uploaded file, + * and allows you to do whatever you want with the file, especially if it + * is an image, and as many times as you want. + * + * It is the ideal class to quickly integrate file upload in your site. + * If the file is an image, you can convert, resize, crop it in many ways. + * You can also apply filters, add borders, text, watermarks, etc... + * That's all you need for a gallery script for instance. Supported formats + * are PNG, JPG, GIF and BMP. + * + * You can also use the class to work on local files, which is especially + * useful to use the image manipulation features. The class also supports + * Flash uploaders. + * + * The class works with PHP 4 and 5, and its error messages can + * be localized at will. + * + * How does it work? + * + * You instanciate the class with the $_FILES['my_field'] array + * where my_field is the field name from your upload form. + * The class will check if the original file has been uploaded + * to its temporary location (alternatively, you can instanciate + * the class with a local filename). + * + * You can then set a number of processing variables to act on the file. + * For instance, you can rename the file, and if it is an image, + * convert and resize it in many ways. + * You can also set what will the class do if the file already exists. + * + * Then you call the function {@link process} to actually perform the actions + * according to the processing parameters you set above. + * It will create new instances of the original file, + * so the original file remains the same between each process. + * The file will be manipulated, and copied to the given location. + * The processing variables will be reset once it is done. + * + * You can repeat setting up a new set of processing variables, + * and calling {@link process} again as many times as you want. + * When you have finished, you can call {@link clean} to delete + * the original uploaded file. + * + * If you don't set any processing parameters and call {@link process} + * just after instanciating the class. The uploaded file will be simply + * copied to the given location without any alteration or checks. + * + * Don't forget to add enctype="multipart/form-data" in your form + * tag
    if you want your form to upload the file. + * + * How to use it?
    + * Create a simple HTML file, with a form such as: + *
    + * 
    + *   
    + *   
    + * 
    + * 
    + * Create a file called upload.php: + *
    + *  $handle = new upload($_FILES['image_field']);
    + *  if ($handle->uploaded) {
    + *      $handle->file_new_name_body   = 'image_resized';
    + *      $handle->image_resize         = true;
    + *      $handle->image_x              = 100;
    + *      $handle->image_ratio_y        = true;
    + *      $handle->process('/home/user/files/');
    + *      if ($handle->processed) {
    + *          echo 'image resized';
    + *          $handle->clean();
    + *      } else {
    + *          echo 'error : ' . $handle->error;
    + *      }
    + *  }
    + * 
    + * + * How to process a file uploaded via XMLHttpRequest?
    + * Use the class as following, the rest being the same as above: + *
    + *  $handle = new upload('php:'.$_SERVER['HTTP_X_FILE_NAME']);
    + * 
    + * Prefixing the argument with "php:" tells the class to retrieve the uploaded data + * in php://input, and the rest is the stream's filename, which is generally in + * $_SERVER['HTTP_X_FILE_NAME']. But you can use any other name you see fit: + *
    + *  $handle = new upload('php:mycustomname.ext');
    + * 
    + * + * How to process local files?
    + * Use the class as following, the rest being the same as above: + *
    + *  $handle = new upload('/home/user/myfile.jpg');
    + * 
    + * + * How to set the language?
    + * Instantiate the class with a second argument being the language code: + *
    + *  $handle = new upload($_FILES['image_field'], 'fr_FR');
    + *  $handle = new upload('/home/user/myfile.jpg', 'fr_FR');
    + * 
    + * + * How to output the resulting file or picture directly to the browser?
    + * Simply call {@link process}() without an argument (or with null as first argument): + *
    + *  $handle = new upload($_FILES['image_field']);
    + *  header('Content-type: ' . $handle->file_src_mime);
    + *  echo $handle->Process();
    + *  die();
    + * 
    + * Or if you want to force the download of the file: + *
    + *  $handle = new upload($_FILES['image_field']);
    + *  header('Content-type: ' . $handle->file_src_mime);
    + *  header("Content-Disposition: attachment; filename=".rawurlencode($handle->file_src_name).";");
    + *  echo $handle->Process();
    + *  die();
    + * 
    + * + * Processing parameters (reset after each process) + *
      + *
    • {@link file_new_name_body} replaces the name body (default: null)
      + *
      $handle->file_new_name_body = 'new name';
    • + *
    • {@link file_name_body_add} appends to the name body (default: null)
      + *
      $handle->file_name_body_add = '_uploaded';
    • + *
    • {@link file_name_body_pre} prepends to the name body (default: null)
      + *
      $handle->file_name_body_pre = 'thumb_';
    • + *
    • {@link file_new_name_ext} replaces the file extension (default: null)
      + *
      $handle->file_new_name_ext = 'txt';
    • + *
    • {@link file_safe_name} formats the filename (spaces changed to _) (default: true)
      + *
      $handle->file_safe_name = true;
    • + *
    • {@link file_force_extension} forces an extension if there is't any (default: true)
      + *
      $handle->file_force_extension = true;
    • + *
    • {@link file_overwrite} sets behaviour if file already exists (default: false)
      + *
      $handle->file_overwrite = true;
    • + *
    • {@link file_auto_rename} automatically renames file if it already exists (default: true)
      + *
      $handle->file_auto_rename = true;
    • + *
    • {@link dir_auto_create} automatically creates destination directory if missing (default: true)
      + *
      $handle->auto_create_dir = true;
    • + *
    • {@link dir_auto_chmod} automatically attempts to chmod the destination directory if not writeable (default: true)
      + *
      $handle->dir_auto_chmod = true;
    • + *
    • {@link dir_chmod} chmod used when creating directory or if directory not writeable (default: 0777)
      + *
      $handle->dir_chmod = 0777;
    • + *
    • {@link file_max_size} sets maximum upload size (default: upload_max_filesize from php.ini)
      + *
      $handle->file_max_size = '1024'; // 1KB
    • + *
    • {@link mime_check} sets if the class check the MIME against the {@link allowed} list (default: true)
      + *
      $handle->mime_check = true;
    • + *
    • {@link no_script} sets if the class turns scripts into text files (default: true)
      + *
      $handle->no_script = false;
    • + *
    • {@link allowed} array of allowed mime-types (or one string). wildcard accepted, as in image/* (default: check {@link Init})
      + *
      $handle->allowed = array('application/pdf','application/msword', 'image/*');
    • + *
    • {@link forbidden} array of forbidden mime-types (or one string). wildcard accepted, as in image/* (default: check {@link Init})
      + *
      $handle->forbidden = array('application/*');
    • + *
    + *
      + *
    • {@link image_convert} if set, image will be converted (possible values : ''|'png'|'jpeg'|'gif'|'bmp'; default: '')
      + *
      $handle->image_convert = 'jpg';
    • + *
    • {@link image_background_color} if set, will forcibly fill transparent areas with the color, in hexadecimal (default: null)
      + *
      $handle->image_background_color = '#FF00FF';
    • + *
    • {@link image_default_color} fallback color background color for non alpha-transparent output formats, such as JPEG or BMP, in hexadecimal (default: #FFFFFF)
      + *
      $handle->image_default_color = '#FF00FF';
    • + *
    • {@link png_compression} sets the compression level for PNG images, between 1 (fast but large files) and 9 (slow but smaller files) (default: null (Zlib default))
      + *
      $handle->png_compression = 9;
    • + *
    • {@link jpeg_quality} sets the compression quality for JPEG images (default: 85)
      + *
      $handle->jpeg_quality = 50;
    • + *
    • {@link jpeg_size} if set to a size in bytes, will approximate {@link jpeg_quality} so the output image fits within the size (default: null)
      + *
      $handle->jpeg_size = 3072;
    • + *
    • {@link image_interlace} if set to true, the image will be saved interlaced (default: false)
      + *
      $handle->image_interlace = true;
    • + *
    + * The following eight settings can be used to invalidate an upload if the file is an image (note that open_basedir restrictions prevent the use of these settings) + *
      + *
    • {@link image_max_width} if set to a dimension in pixels, the upload will be invalid if the image width is greater (default: null)
      + *
      $handle->image_max_width = 200;
    • + *
    • {@link image_max_height} if set to a dimension in pixels, the upload will be invalid if the image height is greater (default: null)
      + *
      $handle->image_max_height = 100;
    • + *
    • {@link image_max_pixels} if set to a number of pixels, the upload will be invalid if the image number of pixels is greater (default: null)
      + *
      $handle->image_max_pixels = 50000;
    • + *
    • {@link image_max_ratio} if set to a aspect ratio (width/height), the upload will be invalid if the image apect ratio is greater (default: null)
      + *
      $handle->image_max_ratio = 1.5;
    • + *
    • {@link image_min_width} if set to a dimension in pixels, the upload will be invalid if the image width is lower (default: null)
      + *
      $handle->image_min_width = 100;
    • + *
    • {@link image_min_height} if set to a dimension in pixels, the upload will be invalid if the image height is lower (default: null)
      + *
      $handle->image_min_height = 500;
    • + *
    • {@link image_min_pixels} if set to a number of pixels, the upload will be invalid if the image number of pixels is lower (default: null)
      + *
      $handle->image_min_pixels = 20000;
    • + *
    • {@link image_min_ratio} if set to a aspect ratio (width/height), the upload will be invalid if the image apect ratio is lower (default: null)
      + *
      $handle->image_min_ratio = 0.5;
    • + *
    + *
      + *
    • {@link image_resize} determines is an image will be resized (default: false)
      + *
      $handle->image_resize = true;
    • + *
    + * The following variables are used only if {@link image_resize} == true + *
      + *
    • {@link image_x} destination image width (default: 150)
      + *
      $handle->image_x = 100;
    • + *
    • {@link image_y} destination image height (default: 150)
      + *
      $handle->image_y = 200;
    • + *
    + * Use either one of the following + *
      + *
    • {@link image_ratio} if true, resize image conserving the original sizes ratio, using {@link image_x} AND {@link image_y} as max sizes if true (default: false)
      + *
      $handle->image_ratio = true;
    • + *
    • {@link image_ratio_crop} if true, resize image conserving the original sizes ratio, using {@link image_x} AND {@link image_y} as max sizes, and cropping excedent to fill the space. setting can also be a string, with one or more from 'TBLR', indicating which side of the image will be kept while cropping (default: false)
      + *
      $handle->image_ratio_crop = true;
    • + *
    • {@link image_ratio_fill} if true, resize image conserving the original sizes ratio, using {@link image_x} AND {@link image_y} as max sizes, fitting the image in the space and coloring the remaining space. setting can also be a string, with one or more from 'TBLR', indicating which side of the space the image will be in (default: false)
      + *
      $handle->image_ratio_fill = true;
    • + *
    • {@link image_ratio_no_zoom_in} same as {@link image_ratio}, but won't resize if the source image is smaller than {@link image_x} x {@link image_y} (default: false)
      + *
      $handle->image_ratio_no_zoom_in = true;
    • + *
    • {@link image_ratio_no_zoom_out} same as {@link image_ratio}, but won't resize if the source image is bigger than {@link image_x} x {@link image_y} (default: false)
      + *
      $handle->image_ratio_no_zoom_out = true;
    • + *
    • {@link image_ratio_x} if true, resize image, calculating {@link image_x} from {@link image_y} and conserving the original sizes ratio (default: false)
      + *
      $handle->image_ratio_x = true;
    • + *
    • {@link image_ratio_y} if true, resize image, calculating {@link image_y} from {@link image_x} and conserving the original sizes ratio (default: false)
      + *
      $handle->image_ratio_y = true;
    • + *
    • {@link image_ratio_pixels} if set to a long integer, resize image, calculating {@link image_y} and {@link image_x} to match a the number of pixels (default: false)
      + *
      $handle->image_ratio_pixels = 25000;
    • + *
    + * The following image manipulations require GD2+ + *
      + *
    • {@link image_brightness} if set, corrects the brightness. value between -127 and 127 (default: null)
      + *
      $handle->image_brightness = 40;
    • + *
    • {@link image_contrast} if set, corrects the contrast. value between -127 and 127 (default: null)
      + *
      $handle->image_contrast = 50;
    • + *
    • {@link image_opacity} if set, changes the image opacity. value between 0 and 100 (default: null)
      + *
      $handle->image_opacity = 50;
    • + *
    • {@link image_tint_color} if set, will tint the image with a color, value as hexadecimal #FFFFFF (default: null)
      + *
      $handle->image_tint_color = '#FF0000';
    • + *
    • {@link image_overlay_color} if set, will add a colored overlay, value as hexadecimal #FFFFFF (default: null)
      + *
      $handle->image_overlay_color = '#FF0000';
    • + *
    • {@link image_overlay_opacity} used when {@link image_overlay_color} is set, determines the opacity (default: 50)
      + *
      $handle->image_overlay_opacity = 20;
    • + *
    • {@link image_negative} inverts the colors in the image (default: false)
      + *
      $handle->image_negative = true;
    • + *
    • {@link image_greyscale} transforms an image into greyscale (default: false)
      + *
      $handle->image_greyscale = true;
    • + *
    • {@link image_threshold} applies a threshold filter. value between -127 and 127 (default: null)
      + *
      $handle->image_threshold = 20;
    • + *
    • {@link image_pixelate} pixelate an image, value is block size (default: null)
      + *
      $handle->image_pixelate = 10;
    • + *
    • {@link image_unsharp} applies an unsharp mask, with alpha transparency support (default: false)
      + *
      $handle->image_unsharp = true;
    • + *
    • {@link image_unsharp_amount} unsharp mask amount, typically 50 - 200 (default: 80)
      + *
      $handle->image_unsharp_amount = 120;
    • + *
    • {@link image_unsharp_radius} unsharp mask radius, typically 0.5 - 1 (default: 0.5)
      + *
      $handle->image_unsharp_radius = 1;
    • + *
    • {@link image_unsharp_threshold} unsharp mask threshold, typically 0 - 5 (default: 1)
      + *
      $handle->image_unsharp_threshold = 0;
    • + *
    + *
      + *
    • {@link image_text} creates a text label on the image, value is a string, with eventual replacement tokens (default: null)
      + *
      $handle->image_text = 'test';
    • + *
    • {@link image_text_direction} text label direction, either 'h' horizontal or 'v' vertical (default: 'h')
      + *
      $handle->image_text_direction = 'v';
    • + *
    • {@link image_text_color} text color for the text label, in hexadecimal (default: #FFFFFF)
      + *
      $handle->image_text_color = '#FF0000';
    • + *
    • {@link image_text_opacity} text opacity on the text label, integer between 0 and 100 (default: 100)
      + *
      $handle->image_text_opacity = 50;
    • + *
    • {@link image_text_background} text label background color, in hexadecimal (default: null)
      + *
      $handle->image_text_background = '#FFFFFF';
    • + *
    • {@link image_text_background_opacity} text label background opacity, integer between 0 and 100 (default: 100)
      + *
      $handle->image_text_background_opacity = 50;
    • + *
    • {@link image_text_font} built-in font for the text label, from 1 to 5. 1 is the smallest (default: 5)
      + *
      $handle->image_text_font = 4;
    • + *
    • {@link image_text_x} absolute text label position, in pixels from the left border. can be negative (default: null)
      + *
      $handle->image_text_x = 5;
    • + *
    • {@link image_text_y} absolute text label position, in pixels from the top border. can be negative (default: null)
      + *
      $handle->image_text_y = 5;
    • + *
    • {@link image_text_position} text label position withing the image, a combination of one or two from 'TBLR': top, bottom, left, right (default: null)
      + *
      $handle->image_text_position = 'LR';
    • + *
    • {@link image_text_padding} text label padding, in pixels. can be overridden by {@link image_text_padding_x} and {@link image_text_padding_y} (default: 0)
      + *
      $handle->image_text_padding = 5;
    • + *
    • {@link image_text_padding_x} text label horizontal padding (default: null)
      + *
      $handle->image_text_padding_x = 2;
    • + *
    • {@link image_text_padding_y} text label vertical padding (default: null)
      + *
      $handle->image_text_padding_y = 10;
    • + *
    • {@link image_text_alignment} text alignment when text has multiple lines, either 'L', 'C' or 'R' (default: 'C')
      + *
      $handle->image_text_alignment = 'R';
    • + *
    • {@link image_text_line_spacing} space between lines in pixels, when text has multiple lines (default: 0)
      + *
      $handle->image_text_line_spacing = 3;
    • + *
    + *
      + *
    • {@link image_flip} flips image, wither 'h' horizontal or 'v' vertical (default: null)
      + *
      $handle->image_flip = 'h';
    • + *
    • {@link image_rotate} rotates image. possible values are 90, 180 and 270 (default: null)
      + *
      $handle->image_rotate = 90;
    • + *
    • {@link image_crop} crops image. accepts 4, 2 or 1 values as 'T R B L' or 'TB LR' or 'TBLR'. dimension can be 20, or 20px or 20% (default: null)
      + *
      $handle->image_crop = array(50,40,30,20); OR '-20 20%'...
    • + *
    • {@link image_precrop} crops image, before an eventual resizing. accepts 4, 2 or 1 values as 'T R B L' or 'TB LR' or 'TBLR'. dimension can be 20, or 20px or 20% (default: null)
      + *
      $handle->image_precrop = array(50,40,30,20); OR '-20 20%'...
    • + *
    + *
      + *
    • {@link image_bevel} adds a bevel border to the image. value is thickness in pixels (default: null)
      + *
      $handle->image_bevel = 20;
    • + *
    • {@link image_bevel_color1} top and left bevel color, in hexadecimal (default: #FFFFFF)
      + *
      $handle->image_bevel_color1 = '#FFFFFF';
    • + *
    • {@link image_bevel_color2} bottom and right bevel color, in hexadecimal (default: #000000)
      + *
      $handle->image_bevel_color2 = '#000000';
    • + *
    • {@link image_border} adds a unicolor border to the image. accepts 4, 2 or 1 values as 'T R B L' or 'TB LR' or 'TBLR'. dimension can be 20, or 20px or 20% (default: null)
      + *
      $handle->image_border = '3px'; OR '-20 20%' OR array(3,2)...
    • + *
    • {@link image_border_color} border color, in hexadecimal (default: #FFFFFF)
      + *
      $handle->image_border_color = '#FFFFFF';
    • + *
    • {@link image_border_opacity} border opacity, integer between 0 and 100 (default: 100)
      + *
      $handle->image_border_opacity = 50;
    • + *
    • {@link image_border_transparent} adds a fading-to-transparent border to the image. accepts 4, 2 or 1 values as 'T R B L' or 'TB LR' or 'TBLR'. dimension can be 20, or 20px or 20% (default: null)
      + *
      $handle->image_border_transparent = '3px'; OR '-20 20%' OR array(3,2)...
    • + *
    • {@link image_frame} type of frame: 1=flat 2=crossed (default: null)
      + *
      $handle->image_frame = 2;
    • + *
    • {@link image_frame_colors} list of hex colors, in an array or a space separated string (default: '#FFFFFF #999999 #666666 #000000')
      + *
      $handle->image_frame_colors = array('#999999',  '#FF0000', '#666666', '#333333', '#000000');
    • + *
    • {@link image_frame_opacity} frame opacity, integer between 0 and 100 (default: 100)
      + *
      $handle->image_frame_opacity = 50;
    • + *
    + *
      + *
    • {@link image_watermark} adds a watermark on the image, value is a local filename. accepted files are GIF, JPG, BMP, PNG and PNG alpha (default: null)
      + *
      $handle->image_watermark = 'watermark.png';
    • + *
    • {@link image_watermark_x} absolute watermark position, in pixels from the left border. can be negative (default: null)
      + *
      $handle->image_watermark_x = 5;
    • + *
    • {@link image_watermark_y} absolute watermark position, in pixels from the top border. can be negative (default: null)
      + *
      $handle->image_watermark_y = 5;
    • + *
    • {@link image_watermark_position} watermark position withing the image, a combination of one or two from 'TBLR': top, bottom, left, right (default: null)
      + *
      $handle->image_watermark_position = 'LR';
    • + *
    • {@link image_watermark_no_zoom_in} prevents the watermark to be resized up if it is smaller than the image (default: true)
      + *
      $handle->image_watermark_no_zoom_in = false;
    • + *
    • {@link image_watermark_no_zoom_out} prevents the watermark to be resized down if it is bigger than the image (default: false)
      + *
      $handle->image_watermark_no_zoom_out = true;
    • + *
    + *
      + *
    • {@link image_reflection_height} if set, a reflection will be added. Format is either in pixels or percentage, such as 40, '40', '40px' or '40%' (default: null)
      + *
      $handle->image_reflection_height = '25%';
    • + *
    • {@link image_reflection_space} space in pixels between the source image and the reflection, can be negative (default: null)
      + *
      $handle->image_reflection_space = 3;
    • + *
    • {@link image_reflection_color} reflection background color, in hexadecimal. Now deprecated in favor of {@link image_default_color} (default: #FFFFFF)
      + *
      $handle->image_default_color = '#000000';
    • + *
    • {@link image_reflection_opacity} opacity level at which the reflection starts, integer between 0 and 100 (default: 60)
      + *
      $handle->image_reflection_opacity = 60;
    • + *
    + * + * Values that can be read before calling {@link process}() + *
      + *
    • {@link file_src_name} Source file name
    • + *
    • {@link file_src_name_body} Source file name body
    • + *
    • {@link file_src_name_ext} Source file extension
    • + *
    • {@link file_src_pathname} Source file complete path and name
    • + *
    • {@link file_src_mime} Source file mime type
    • + *
    • {@link file_src_size} Source file size in bytes
    • + *
    • {@link file_src_error} Upload error code
    • + *
    • {@link file_is_image} Boolean flag, true if the file is a supported image type
    • + *
    + * If the file is a supported image type (and open_basedir restrictions allow it) + *
      + *
    • {@link image_src_x} Source file width in pixels
    • + *
    • {@link image_src_y} Source file height in pixels
    • + *
    • {@link image_src_pixels} Source file number of pixels
    • + *
    • {@link image_src_type} Source file type (png, jpg, gif or bmp)
    • + *
    • {@link image_src_bits} Source file color depth
    • + *
    + * + * Values that can be read after calling {@link process}() + *
      + *
    • {@link file_dst_path} Destination file path
    • + *
    • {@link file_dst_name_body} Destination file name body
    • + *
    • {@link file_dst_name_ext} Destination file extension
    • + *
    • {@link file_dst_name} Destination file name
    • + *
    • {@link file_dst_pathname} Destination file complete path and name
    • + *
    + * If the file is a supported image type + *
      + *
    • {@link image_dst_x} Destination file width
    • + *
    • {@link image_dst_y} Destination file height
    • + *
    • {@link image_convert} Destination file format
    • + *
    + * + * Requirements + * + * Most of the image operations require GD. GD2 is greatly recommended + * + * The class requires PHP 4.3+, and is compatible with PHP5 + * + * Changelog + *
      + *
    • v 0.32 15/01/2013
      + * - add support for XMLHttpRequest uploads
      + * - added {@link image_pixelate}
      + * - added {@link image_interlace}
      + * - added {@link png_compression} to change PNG compressoin level
      + * - deactivate exec() if Suhosin is enabled
      + * - add more extension to dangerous scripts detection
      + * - imagejpeg takes null as second argument since PHP 5.4
      + * - default PECL Fileinfo MAGIC path to null
      + * - set gd.jpeg_ignore_warning to true by default
      + * - fixed file name normalization
    • + *
    • v 0.31 11/04/2011
      + * - added application/x-rar MIME type
      + * - make sure exec() and ini_get_all()function are not disabled if we want to use them
      + * - make sure that we don't divide by zero when calculating JPEG size
      + * - {@link allowed} and {@link forbidden} can now accept strings
      + * - try to guess the file extension from the MIME type if there is no file extension
      + * - better class properties when changing the file extension
      + * - added {@link file_force_extension} to allow extension-less files if needed
      + * - better file safe conversion of the filename
      + * - allow shorthand byte values, such as 1K, 2M, 3G for {@link file_max_size} and {@link jpeg_size}
      + * - added {@link image_opacity} to change picture opacity
      + * - added {@link image_border_opacity} to allow semi-transparent borders
      + * - added {@link image_frame_opacity} to allow semi-transparent frames
      + * - added {@link image_border_transparent} to allow borders fading to transparent
      + * - duplicated {@link image_overlay_percent} into {@link image_overlay_opacity}
      + * - duplicated {@link image_text_percent} into {@link image_text_opacity}
      + * - duplicated {@link image_text_background_percent} into {@link image_text_background_opacity}
    • + *
    • v 0.30 05/09/2010
      + * - implemented an unsharp mask, with alpha transparency support, activated if {@link image_unsharp} is true. added {@link image_unsharp_amount}, {@link image_unsharp_radius}, and {@link image_unsharp_threshold}
      + * - added text/rtf MIME type, and no_script exception
      + * - corrected bug when {@link no_script} is activated and several process() are called
      + * - better error handling for finfo
      + * - display upload_max_filesize information from php.ini in the log
      + * - automatic extension for extension-less images
      + * - fixed {@link image_ratio_fill} top and left filling
      + * - fixed alphablending issue when applying a transparent PNG watermark on a transparent PNG
      + * - added {@link image_watermark_no_zoom_in} and {@link image_watermark_no_zoom_out} to allow the watermark to be resized down (or up) to fit in the image. By default, the watermark may be resized down, but not up.
    • + *
    • v 0.29 03/02/2010
      + * - added protection against malicious images
      + * - added zip and torrent MIME type
      + * - replaced split() with explode()
      + * - initialise image_dst_x/y with image_src_x/y
      + * - removed {@link mime_fileinfo}, {@link mime_file}, {@link mime_magic} and {@link mime_getimagesize} from the docs since they are used before {@link process}
      + * - added more extensions and MIME types
      + * - improved MIME type validation
      + * - improved logging
    • + *
    • v 0.28 10/08/2009
      + * - replaced ereg functions to be compatible with PHP 5.3
      + * - added flv MIME type
      + * - improved MIME type detection
      + * - added {@link file_name_body_pre} to prepend a string to the file name
      + * - added {@link mime_fileinfo}, {@link mime_file}, {@link mime_magic} and {@link mime_getimagesize} so that it is possible to deactivate some MIME type checking method
      + * - use exec() rather than shell_exec(), to play better with safe mode
      + * - added some error messages
      + * - fix bug when checking on conditions, {@link processed} wasn't propagated properly
    • + *
    • v 0.27 14/05/2009
      + * - look for the language files directory from __FILE__
      + * - deactivate {@link file_auto_rename} if {@link file_overwrite} is set
      + * - improved transparency replacement for true color images
      + * - fixed calls to newer version of UNIX file utility
      + * - fixed error when using PECL Fileinfo extension in SAFE MODE, and when using the finfo class
      + * - added {@link image_precrop} to crop the image before an eventual resizing
    • + *
    • v 0.26 13/11/2008
      + * - rewrote conversion from palette to true color to handle transparency better
      + * - fixed imagecopymergealpha() when the overlayed image is of wrong dimensions
      + * - fixed imagecreatenew() when the image to create have less than 1 pixels width or height
      + * - rewrote MIME type detection to be more secure and not rely on browser information; now using Fileinfo PECL extension, UNIX file() command, MIME magic, and getimagesize(), in that order
      + * - added support for Flash uploaders
      + * - some bug fixing and error handling
    • + *
    • v 0.25 17/11/2007
      + * - added translation files and mechanism to instantiate the class with a language different from English
      + * - added {@link forbidden} to set an array of forbidden MIME types
      + * - implemented support for simple wildcards in {@link allowed} and {@link forbidden}, such as image/*
      + * - preset the file extension to the desired conversion format when converting an image
      + * - added read and write support for BMP images
      + * - added a flag {@link file_is_image} to determine if the file is a supported image type
      + * - the class now provides some information about the image, before calling {@link process}(). Available are {@link image_src_x}, {@link image_src_y} and the newly introduced {@link image_src_bits}, {@link image_src_pixels} and {@link image_src_type}. Note that this will not work if open_basedir restrictions are in place
      + * - improved logging; now provides useful system information
      + * - added some more pre-processing checks for files that are images: {@link image_max_width}, {@link image_max_height}, {@link image_max_pixels}, {@link image_max_ratio}, {@link image_min_width}, {@link image_min_height}, {@link image_min_pixels} and {@link image_min_ratio}
      + * - added {@link image_ratio_pixels} to resize an image to a number of pixels, keeping aspect ratio
      + * - added {@link image_is_palette} and {@link image_is_transparent} and {@link image_transparent_color} for GIF images
      + * - added {@link image_default_color} to define a fallback color for non alpha-transparent output formats, such as JPEG or BMP
      + * - changed {@link image_background_color}, which now forces transparent areas to be painted
      + * - improved reflections and color overlays so that it works with alpha transparent images
      + * - {@link image_reflection_color} is now deprecated in favour of {@link image_default_color}
      + * - transparent PNGs are now processed in true color, and fully preserving the alpha channel when doing merges
      + * - transparent GIFs are now automatically detected. {@link preserve_transparency} is deprecated
      + * - transparent true color images can be saved as GIF while retaining transparency, semi transparent areas being merged with {@link image_default_color}
      + * - transparent true color images can be saved as JPG/BMP with the semi transparent areas being merged with {@link image_default_color}
      + * - fixed conversion of images to true color
      + * - the class can now output the uploaded files content as the return value of process() if the function is called with an empty or null argumenti, or no argument
    • + *
    • v 0.24 25/05/2007
      + * - added {@link image_background_color}, to set the default background color of an image
      + * - added possibility of using replacement tokens in text labels
      + * - changed default JPEG quality to 85
      + * - fixed a small bug when using greyscale filter and associated filters
      + * - added {@link image_ratio_fill} in order to fit an image within some dimensions and color the remaining space. Very similar to {@link image_ratio_crop}
      + * - improved the recursive creation of directories
      + * - the class now converts palette based images to true colors before doing graphic manipulations
    • + *
    • v 0.23 23/12/2006
      + * - fixed a bug when processing more than once the same uploaded file. If there is an open_basedir restriction, the class now creates a temporary file for the first call to process(). This file will be used for subsequent processes, and will be deleted upon calling clean()
    • + *
    • v 0.22 16/12/2006
      + * - added automatic creation of a temporary file if the upload directory is not within open_basedir
      + * - fixed a bug which was preventing to work on a local file by overwriting it with its processed copy
      + * - added MIME types video/x-ms-wmv and image/x-png and fixed PNG support for IE weird MIME types
      + * - modified {@link image_ratio_crop} so it can accept one or more from string 'TBLR', determining which side of the image is kept while cropping
      + * - added support for multiple lines in the text, using "\n" as a line break
      + * - added {@link image_text_line_spacing} which allow to set the space between several lines of text
      + * - added {@link image_text_alignment} which allow to set the alignment when text has several lines
      + * - {@link image_text_font} can now be set to the path of a GDF font to load external fonts
      + * - added {@link image_reflection_height} to create a reflection of the source image, which height is in pixels or percentage
      + * - added {@link image_reflection_space} to set the space in pixels between the source image and the reflection
      + * - added {@link image_reflection_color} to set the reflection background color
      + * - added {@link image_reflection_opacity} to set the initial level of opacity of the reflection
    • + *
    • v 0.21 30/09/2006
      + * - added {@link image_ratio_crop} which resizes within {@link image_x} and {@link image_y}, keeping ratio, but filling the space by cropping excedent of image
      + * - added {@link mime_check}, which default is true, to set checks against {@link allowed} MIME list
      + * - if MIME is empty, the class now triggers an error
      + * - color #000000 is OK for {@link image_text_color}, and related text transparency bug fixed
      + * - {@link gd_version}() now uses gd_info(), or else phpinfo()
      + * - fixed path issue when the destination path has no trailing slash on Windows systems
      + * - removed inline functions to be fully PHP5 compatible
    • + *
    • v 0.20 11/08/2006
      + * - added some more error checking and messages (GD presence, permissions...)
      + * - fix when uploading files without extension
      + * - changed values for {@link image_brightness} and {@link image_contrast} to be between -127 and 127
      + * - added {@link dir_auto_create} to automatically and recursively create destination directory if missing.
      + * - added {@link dir_auto_chmod} to automatically chmod the destination directory if not writeable.
      + * - added {@link dir_chmod} to set the default chmod to use.
      + * - added {@link image_crop} to crop images
      + * - added {@link image_negative} to invert the colors on the image
      + * - added {@link image_greyscale} to turn the image into greyscale
      + * - added {@link image_threshold} to apply a threshold filter on the image
      + * - added {@link image_bevel}, {@link image_bevel_color1} and {@link image_bevel_color2} to add a bevel border
      + * - added {@link image_border} and {@link image_border_color} to add a single color border
      + * - added {@link image_frame} and {@link image_frame_colors} to add a multicolored frame
    • + *
    • v 0.19 29/03/2006
      + * - class is now compatible i18n (thanks Sylwester).
      + * - the class can mow manipulate local files, not only uploaded files (instanciate the class with a local filename).
      + * - {@link file_safe_name} has been improved a bit.
      + * - added {@link image_brightness}, {@link image_contrast}, {@link image_tint_color}, {@link image_overlay_color} and {@link image_overlay_percent} to do color manipulation on the images.
      + * - added {@link image_text} and all derivated settings to add a text label on the image.
      + * - added {@link image_watermark} and all derivated settings to add a watermark image on the image.
      + * - added {@link image_flip} and {@link image_rotate} for more image manipulations
      + * - added {@link jpeg_size} to calculate the JPG compression quality in order to fit within one filesize.
    • + *
    • v 0.18 02/02/2006
      + * - added {@link no_script} to turn dangerous scripts into text files.
      + * - added {@link mime_magic_check} to set the class to use mime_magic.
      + * - added {@link preserve_transparency} *experimental*. Thanks Gregor.
      + * - fixed size and mime checking, wasn't working :/ Thanks Willem.
      + * - fixed memory leak when resizing images.
      + * - when resizing, it is not necessary anymore to set {@link image_convert}.
      + * - il is now possible to simply convert an image, with no resizing.
      + * - sets the default {@link file_max_size} to upload_max_filesize from php.ini. Thanks Edward
    • + *
    • v 0.17 28/05/2005
      + * - the class can be used with any version of GD.
      + * - added security check on the file with a list of mime-types.
      + * - changed the license to GPL v2 only
    • + *
    • v 0.16 19/05/2005
      + * - added {@link file_auto_rename} automatic file renaming if the same filename already exists.
      + * - added {@link file_safe_name} safe formatting of the filename (spaces to _underscores so far).
      + * - added some more error reporting to avoid crash if GD is not present
    • + *
    • v 0.15 16/04/2005
      + * - added JPEG compression quality setting. Thanks Vad
    • + *
    • v 0.14 14/03/2005
      + * - reworked the class file to allow parsing with phpDocumentor
    • + *
    • v 0.13 07/03/2005
      + * - fixed a bug with {@link image_ratio}. Thanks Justin.
      + * - added {@link image_ratio_no_zoom_in} and {@link image_ratio_no_zoom_out}
    • + *
    • v 0.12 21/01/2005
      + * - added {@link image_ratio} to resize within max values, keeping image ratio
    • + *
    • v 0.11 22/08/2003
      + * - update for GD2 (changed imageresized() into imagecopyresampled() and imagecreate() into imagecreatetruecolor())
    • + *
    + * + * @package cmf + * @subpackage external + */ +class upload { + + + /** + * Class version + * + * @access public + * @var string + */ + var $version; + + /** + * Uploaded file name + * + * @access public + * @var string + */ + var $file_src_name; + + /** + * Uploaded file name body (i.e. without extension) + * + * @access public + * @var string + */ + var $file_src_name_body; + + /** + * Uploaded file name extension + * + * @access public + * @var string + */ + var $file_src_name_ext; + + /** + * Uploaded file MIME type + * + * @access public + * @var string + */ + var $file_src_mime; + + /** + * Uploaded file size, in bytes + * + * @access public + * @var double + */ + var $file_src_size; + + /** + * Holds eventual PHP error code from $_FILES + * + * @access public + * @var string + */ + var $file_src_error; + + /** + * Uloaded file name, including server path + * + * @access public + * @var string + */ + var $file_src_pathname; + + /** + * Uloaded file name temporary copy + * + * @access private + * @var string + */ + var $file_src_temp; + + /** + * Destination file name + * + * @access public + * @var string + */ + var $file_dst_path; + + /** + * Destination file name + * + * @access public + * @var string + */ + var $file_dst_name; + + /** + * Destination file name body (i.e. without extension) + * + * @access public + * @var string + */ + var $file_dst_name_body; + + /** + * Destination file extension + * + * @access public + * @var string + */ + var $file_dst_name_ext; + + /** + * Destination file name, including path + * + * @access public + * @var string + */ + var $file_dst_pathname; + + /** + * Source image width + * + * @access public + * @var integer + */ + var $image_src_x; + + /** + * Source image height + * + * @access public + * @var integer + */ + var $image_src_y; + + /** + * Source image color depth + * + * @access public + * @var integer + */ + var $image_src_bits; + + /** + * Number of pixels + * + * @access public + * @var long + */ + var $image_src_pixels; + + /** + * Type of image (png, gif, jpg or bmp) + * + * @access public + * @var string + */ + var $image_src_type; + + /** + * Destination image width + * + * @access public + * @var integer + */ + var $image_dst_x; + + /** + * Destination image height + * + * @access public + * @var integer + */ + var $image_dst_y; + + /** + * Supported image formats + * + * @access private + * @var array + */ + var $image_supported; + + /** + * Flag to determine if the source file is an image + * + * @access public + * @var boolean + */ + var $file_is_image; + + /** + * Flag set after instanciating the class + * + * Indicates if the file has been uploaded properly + * + * @access public + * @var bool + */ + var $uploaded; + + /** + * Flag stopping PHP upload checks + * + * Indicates whether we instanciated the class with a filename, in which case + * we will not check on the validity of the PHP *upload* + * + * This flag is automatically set to true when working on a local file + * + * Warning: for uploads, this flag MUST be set to false for security reason + * + * @access public + * @var bool + */ + var $no_upload_check; + + /** + * Flag set after calling a process + * + * Indicates if the processing, and copy of the resulting file went OK + * + * @access public + * @var bool + */ + var $processed; + + /** + * Holds eventual error message in plain english + * + * @access public + * @var string + */ + var $error; + + /** + * Holds an HTML formatted log + * + * @access public + * @var string + */ + var $log; + + + // overiddable processing variables + + + /** + * Set this variable to replace the name body (i.e. without extension) + * + * @access public + * @var string + */ + var $file_new_name_body; + + /** + * Set this variable to append a string to the file name body + * + * @access public + * @var string + */ + var $file_name_body_add; + + /** + * Set this variable to prepend a string to the file name body + * + * @access public + * @var string + */ + var $file_name_body_pre; + + /** + * Set this variable to change the file extension + * + * @access public + * @var string + */ + var $file_new_name_ext; + + /** + * Set this variable to format the filename (spaces changed to _) + * + * @access public + * @var boolean + */ + var $file_safe_name; + + /** + * Forces an extension if the source file doesn't have one + * + * If the file is an image, then the correct extension will be added + * Otherwise, a .txt extension will be chosen + * + * @access public + * @var boolean + */ + var $file_force_extension; + + /** + * Set this variable to false if you don't want to check the MIME against the allowed list + * + * This variable is set to true by default for security reason + * + * @access public + * @var boolean + */ + var $mime_check; + + /** + * Set this variable to false in the init() function if you don't want to check the MIME + * with Fileinfo PECL extension. On some systems, Fileinfo is known to be buggy, and you + * may want to deactivate it in the class code directly. + * + * You can also set it with the path of the magic database file. + * If set to true, the class will try to read the MAGIC environment variable + * and if it is empty, will default to the system's default + * If set to an empty string, it will call finfo_open without the path argument + * + * This variable is set to true by default for security reason + * + * @access public + * @var boolean + */ + var $mime_fileinfo; + + /** + * Set this variable to false in the init() function if you don't want to check the MIME + * with UNIX file() command + * + * This variable is set to true by default for security reason + * + * @access public + * @var boolean + */ + var $mime_file; + + /** + * Set this variable to false in the init() function if you don't want to check the MIME + * with the magic.mime file + * + * The function mime_content_type() will be deprecated, + * and this variable will be set to false in a future release + * + * This variable is set to true by default for security reason + * + * @access public + * @var boolean + */ + var $mime_magic; + + /** + * Set this variable to false in the init() function if you don't want to check the MIME + * with getimagesize() + * + * The class tries to get a MIME type from getimagesize() + * If no MIME is returned, it tries to guess the MIME type from the file type + * + * This variable is set to true by default for security reason + * + * @access public + * @var boolean + */ + var $mime_getimagesize; + + /** + * Set this variable to false if you don't want to turn dangerous scripts into simple text files + * + * @access public + * @var boolean + */ + var $no_script; + + /** + * Set this variable to true to allow automatic renaming of the file + * if the file already exists + * + * Default value is true + * + * For instance, on uploading foo.ext,
    + * if foo.ext already exists, upload will be renamed foo_1.ext
    + * and if foo_1.ext already exists, upload will be renamed foo_2.ext
    + * + * Note that this option doesn't have any effect if {@link file_overwrite} is true + * + * @access public + * @var bool + */ + var $file_auto_rename; + + /** + * Set this variable to true to allow automatic creation of the destination + * directory if it is missing (works recursively) + * + * Default value is true + * + * @access public + * @var bool + */ + var $dir_auto_create; + + /** + * Set this variable to true to allow automatic chmod of the destination + * directory if it is not writeable + * + * Default value is true + * + * @access public + * @var bool + */ + var $dir_auto_chmod; + + /** + * Set this variable to the default chmod you want the class to use + * when creating directories, or attempting to write in a directory + * + * Default value is 0777 (without quotes) + * + * @access public + * @var bool + */ + var $dir_chmod; + + /** + * Set this variable tu true to allow overwriting of an existing file + * + * Default value is false, so no files will be overwritten + * + * @access public + * @var bool + */ + var $file_overwrite; + + /** + * Set this variable to change the maximum size in bytes for an uploaded file + * + * Default value is the value upload_max_filesize from php.ini + * + * Value in bytes (integer) or shorthand byte values (string) is allowed. + * The available options are K (for Kilobytes), M (for Megabytes) and G (for Gigabytes) + * + * @access public + * @var double + */ + var $file_max_size; + + /** + * Set this variable to true to resize the file if it is an image + * + * You will probably want to set {@link image_x} and {@link image_y}, and maybe one of the ratio variables + * + * Default value is false (no resizing) + * + * @access public + * @var bool + */ + var $image_resize; + + /** + * Set this variable to convert the file if it is an image + * + * Possibles values are : ''; 'png'; 'jpeg'; 'gif'; 'bmp' + * + * Default value is '' (no conversion)
    + * If {@link resize} is true, {@link convert} will be set to the source file extension + * + * @access public + * @var string + */ + var $image_convert; + + /** + * Set this variable to the wanted (or maximum/minimum) width for the processed image, in pixels + * + * Default value is 150 + * + * @access public + * @var integer + */ + var $image_x; + + /** + * Set this variable to the wanted (or maximum/minimum) height for the processed image, in pixels + * + * Default value is 150 + * + * @access public + * @var integer + */ + var $image_y; + + /** + * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y} + * + * Default value is false + * + * @access public + * @var bool + */ + var $image_ratio; + + /** + * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y} + * + * The image will be resized as to fill the whole space, and excedent will be cropped + * + * Value can also be a string, one or more character from 'TBLR' (top, bottom, left and right) + * If set as a string, it determines which side of the image is kept while cropping. + * By default, the part of the image kept is in the center, i.e. it crops equally on both sides + * + * Default value is false + * + * @access public + * @var mixed + */ + var $image_ratio_crop; + + /** + * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y} + * + * The image will be resized to fit entirely in the space, and the rest will be colored. + * The default color is white, but can be set with {@link image_default_color} + * + * Value can also be a string, one or more character from 'TBLR' (top, bottom, left and right) + * If set as a string, it determines in which side of the space the image is displayed. + * By default, the image is displayed in the center, i.e. it fills the remaining space equally on both sides + * + * Default value is false + * + * @access public + * @var mixed + */ + var $image_ratio_fill; + + /** + * Set this variable to a number of pixels so that {@link image_x} and {@link image_y} are the best match possible + * + * The image will be resized to have approximatively the number of pixels + * The aspect ratio wil be conserved + * + * Default value is false + * + * @access public + * @var mixed + */ + var $image_ratio_pixels; + + /** + * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y}, + * but only if original image is bigger + * + * Default value is false + * + * @access public + * @var bool + */ + var $image_ratio_no_zoom_in; + + /** + * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y}, + * but only if original image is smaller + * + * Default value is false + * + * @access public + * @var bool + */ + var $image_ratio_no_zoom_out; + + /** + * Set this variable to calculate {@link image_x} automatically , using {@link image_y} and conserving ratio + * + * Default value is false + * + * @access public + * @var bool + */ + var $image_ratio_x; + + /** + * Set this variable to calculate {@link image_y} automatically , using {@link image_x} and conserving ratio + * + * Default value is false + * + * @access public + * @var bool + */ + var $image_ratio_y; + + /** + * Set this variable to set a maximum image width, above which the upload will be invalid + * + * Default value is null + * + * @access public + * @var integer + */ + var $image_max_width; + + /** + * Set this variable to set a maximum image height, above which the upload will be invalid + * + * Default value is null + * + * @access public + * @var integer + */ + var $image_max_height; + + /** + * Set this variable to set a maximum number of pixels for an image, above which the upload will be invalid + * + * Default value is null + * + * @access public + * @var long + */ + var $image_max_pixels; + + /** + * Set this variable to set a maximum image aspect ratio, above which the upload will be invalid + * + * Note that ratio = width / height + * + * Default value is null + * + * @access public + * @var float + */ + var $image_max_ratio; + + /** + * Set this variable to set a minimum image width, below which the upload will be invalid + * + * Default value is null + * + * @access public + * @var integer + */ + var $image_min_width; + + /** + * Set this variable to set a minimum image height, below which the upload will be invalid + * + * Default value is null + * + * @access public + * @var integer + */ + var $image_min_height; + + /** + * Set this variable to set a minimum number of pixels for an image, below which the upload will be invalid + * + * Default value is null + * + * @access public + * @var long + */ + var $image_min_pixels; + + /** + * Set this variable to set a minimum image aspect ratio, below which the upload will be invalid + * + * Note that ratio = width / height + * + * Default value is null + * + * @access public + * @var float + */ + var $image_min_ratio; + + /** + * Compression level for PNG images + * + * Between 1 (fast but large files) and 9 (slow but smaller files) + * + * Default value is null (Zlib default) + * + * @access public + * @var integer + */ + var $png_compression; + + /** + * Quality of JPEG created/converted destination image + * + * Default value is 85 + * + * @access public + * @var integer + */ + var $jpeg_quality; + + /** + * Determines the quality of the JPG image to fit a desired file size + * + * The JPG quality will be set between 1 and 100% + * The calculations are approximations. + * + * Value in bytes (integer) or shorthand byte values (string) is allowed. + * The available options are K (for Kilobytes), M (for Megabytes) and G (for Gigabytes) + * + * Default value is null (no calculations) + * + * @access public + * @var integer + */ + var $jpeg_size; + + /** + * Turns the interlace bit on + * + * This is actually used only for JPEG images, and defaults to false + * + * @access public + * @var boolean + */ + var $image_interlace; + + /** + * Preserve transparency when resizing or converting an image (deprecated) + * + * Default value is automatically set to true for transparent GIFs + * This setting is now deprecated + * + * @access public + * @var integer + */ + var $preserve_transparency; + + /** + * Flag set to true when the image is transparent + * + * This is actually used only for transparent GIFs + * + * @access public + * @var boolean + */ + var $image_is_transparent; + + /** + * Transparent color in a palette + * + * This is actually used only for transparent GIFs + * + * @access public + * @var boolean + */ + var $image_transparent_color; + + /** + * Background color, used to paint transparent areas with + * + * If set, it will forcibly remove transparency by painting transparent areas with the color + * This setting will fill in all transparent areas in PNG and GIF, as opposed to {@link image_default_color} + * which will do so only in BMP, JPEG, and alpha transparent areas in transparent GIFs + * This setting overrides {@link image_default_color} + * + * Default value is null + * + * @access public + * @var string + */ + var $image_background_color; + + /** + * Default color for non alpha-transparent images + * + * This setting is to be used to define a background color for semi transparent areas + * of an alpha transparent when the output format doesn't support alpha transparency + * This is useful when, from an alpha transparent PNG image, or an image with alpha transparent features + * if you want to output it as a transparent GIFs for instance, you can set a blending color for transparent areas + * If you output in JPEG or BMP, this color will be used to fill in the previously transparent areas + * + * The default color white + * + * @access public + * @var boolean + */ + var $image_default_color; + + /** + * Flag set to true when the image is not true color + * + * @access public + * @var boolean + */ + var $image_is_palette; + + /** + * Corrects the image brightness + * + * Value can range between -127 and 127 + * + * Default value is null + * + * @access public + * @var integer + */ + var $image_brightness; + + /** + * Corrects the image contrast + * + * Value can range between -127 and 127 + * + * Default value is null + * + * @access public + * @var integer + */ + var $image_contrast; + + /** + * Changes the image opacity + * + * Value can range between 0 and 100 + * + * Default value is null + * + * @access public + * @var integer + */ + var $image_opacity; + + /** + * Applies threshold filter + * + * Value can range between -127 and 127 + * + * Default value is null + * + * @access public + * @var integer + */ + var $image_threshold; + + /** + * Applies a tint on the image + * + * Value is an hexadecimal color, such as #FFFFFF + * + * Default value is null + * + * @access public + * @var string; + */ + var $image_tint_color; + + /** + * Applies a colored overlay on the image + * + * Value is an hexadecimal color, such as #FFFFFF + * + * To use with {@link image_overlay_opacity} + * + * Default value is null + * + * @access public + * @var string; + */ + var $image_overlay_color; + + /** + * Sets the opacity for the colored overlay + * + * Value is a percentage, as an integer between 0 (transparent) and 100 (opaque) + * + * Unless used with {@link image_overlay_color}, this setting has no effect + * + * Default value is 50 + * + * @access public + * @var integer + */ + var $image_overlay_opacity; + + /** + * Soon to be deprecated old form of {@link image_overlay_opacity} + * + * @access public + * @var integer + */ + var $image_overlay_percent; + + /** + * Inverts the color of an image + * + * Default value is FALSE + * + * @access public + * @var boolean; + */ + var $image_negative; + + /** + * Turns the image into greyscale + * + * Default value is FALSE + * + * @access public + * @var boolean; + */ + var $image_greyscale; + + /** + * Pixelate an image + * + * Value is integer, represents the block size + * + * Default value is null + * + * @access public + * @var integer; + */ + var $image_pixelate; + + /** + * Applies an unsharp mask, with alpha transparency support + * + * Beware that this unsharp mask is quite resource-intensive + * + * Default value is FALSE + * + * @access public + * @var boolean; + */ + var $image_unsharp; + + /** + * Sets the unsharp mask amount + * + * Value is an integer between 0 and 500, typically between 50 and 200 + * + * Unless used with {@link image_unsharp}, this setting has no effect + * + * Default value is 80 + * + * @access public + * @var integer + */ + var $image_unsharp_amount; + + /** + * Sets the unsharp mask radius + * + * Value is an integer between 0 and 50, typically between 0.5 and 1 + * It is not recommended to change it, the default works best + * + * Unless used with {@link image_unsharp}, this setting has no effect + * + * From PHP 5.1, imageconvolution is used, and this setting has no effect + * + * Default value is 0.5 + * + * @access public + * @var integer + */ + var $image_unsharp_radius; + + /** + * Sets the unsharp mask threshold + * + * Value is an integer between 0 and 255, typically between 0 and 5 + * + * Unless used with {@link image_unsharp}, this setting has no effect + * + * Default value is 1 + * + * @access public + * @var integer + */ + var $image_unsharp_threshold; + + /** + * Adds a text label on the image + * + * Value is a string, any text. Text will not word-wrap, although you can use breaklines in your text "\n" + * + * If set, this setting allow the use of all other settings starting with image_text_ + * + * Replacement tokens can be used in the string: + *
    +     * gd_version    src_name       src_name_body src_name_ext
    +     * src_pathname  src_mime       src_x         src_y
    +     * src_type      src_bits       src_pixels
    +     * src_size      src_size_kb    src_size_mb   src_size_human
    +     * dst_path      dst_name_body  dst_pathname
    +     * dst_name      dst_name_ext   dst_x         dst_y
    +     * date          time           host          server        ip
    +     * 
    + * The tokens must be enclosed in square brackets: [dst_x] will be replaced by the width of the picture + * + * Default value is null + * + * @access public + * @var string; + */ + var $image_text; + + /** + * Sets the text direction for the text label + * + * Value is either 'h' or 'v', as in horizontal and vertical + * + * Default value is h (horizontal) + * + * @access public + * @var string; + */ + var $image_text_direction; + + /** + * Sets the text color for the text label + * + * Value is an hexadecimal color, such as #FFFFFF + * + * Default value is #FFFFFF (white) + * + * @access public + * @var string; + */ + var $image_text_color; + + /** + * Sets the text opacity in the text label + * + * Value is a percentage, as an integer between 0 (transparent) and 100 (opaque) + * + * Default value is 100 + * + * @access public + * @var integer + */ + var $image_text_opacity; + + /** + * Soon to be deprecated old form of {@link image_text_opacity} + * + * @access public + * @var integer + */ + var $image_text_percent; + + /** + * Sets the text background color for the text label + * + * Value is an hexadecimal color, such as #FFFFFF + * + * Default value is null (no background) + * + * @access public + * @var string; + */ + var $image_text_background; + + /** + * Sets the text background opacity in the text label + * + * Value is a percentage, as an integer between 0 (transparent) and 100 (opaque) + * + * Default value is 100 + * + * @access public + * @var integer + */ + var $image_text_background_opacity; + + /** + * Soon to be deprecated old form of {@link image_text_background_opacity} + * + * @access public + * @var integer + */ + var $image_text_background_percent; + + /** + * Sets the text font in the text label + * + * Value is a an integer between 1 and 5 for GD built-in fonts. 1 is the smallest font, 5 the biggest + * Value can also be a string, which represents the path to a GDF font. The font will be loaded into GD, and used as a built-in font. + * + * Default value is 5 + * + * @access public + * @var mixed; + */ + var $image_text_font; + + /** + * Sets the text label position within the image + * + * Value is one or two out of 'TBLR' (top, bottom, left, right) + * + * The positions are as following: + *
    +     *                        TL  T  TR
    +     *                        L       R
    +     *                        BL  B  BR
    +     * 
    + * + * Default value is null (centered, horizontal and vertical) + * + * Note that is {@link image_text_x} and {@link image_text_y} are used, this setting has no effect + * + * @access public + * @var string; + */ + var $image_text_position; + + /** + * Sets the text label absolute X position within the image + * + * Value is in pixels, representing the distance between the left of the image and the label + * If a negative value is used, it will represent the distance between the right of the image and the label + * + * Default value is null (so {@link image_text_position} is used) + * + * @access public + * @var integer + */ + var $image_text_x; + + /** + * Sets the text label absolute Y position within the image + * + * Value is in pixels, representing the distance between the top of the image and the label + * If a negative value is used, it will represent the distance between the bottom of the image and the label + * + * Default value is null (so {@link image_text_position} is used) + * + * @access public + * @var integer + */ + var $image_text_y; + + /** + * Sets the text label padding + * + * Value is in pixels, representing the distance between the text and the label background border + * + * Default value is 0 + * + * This setting can be overriden by {@link image_text_padding_x} and {@link image_text_padding_y} + * + * @access public + * @var integer + */ + var $image_text_padding; + + /** + * Sets the text label horizontal padding + * + * Value is in pixels, representing the distance between the text and the left and right label background borders + * + * Default value is null + * + * If set, this setting overrides the horizontal part of {@link image_text_padding} + * + * @access public + * @var integer + */ + var $image_text_padding_x; + + /** + * Sets the text label vertical padding + * + * Value is in pixels, representing the distance between the text and the top and bottom label background borders + * + * Default value is null + * + * If set, his setting overrides the vertical part of {@link image_text_padding} + * + * @access public + * @var integer + */ + var $image_text_padding_y; + + /** + * Sets the text alignment + * + * Value is a string, which can be either 'L', 'C' or 'R' + * + * Default value is 'C' + * + * This setting is relevant only if the text has several lines. + * + * @access public + * @var string; + */ + var $image_text_alignment; + + /** + * Sets the text line spacing + * + * Value is an integer, in pixels + * + * Default value is 0 + * + * This setting is relevant only if the text has several lines. + * + * @access public + * @var integer + */ + var $image_text_line_spacing; + + /** + * Sets the height of the reflection + * + * Value is an integer in pixels, or a string which format can be in pixels or percentage. + * For instance, values can be : 40, '40', '40px' or '40%' + * + * Default value is null, no reflection + * + * @access public + * @var mixed; + */ + var $image_reflection_height; + + /** + * Sets the space between the source image and its relection + * + * Value is an integer in pixels, which can be negative + * + * Default value is 2 + * + * This setting is relevant only if {@link image_reflection_height} is set + * + * @access public + * @var integer + */ + var $image_reflection_space; + + /** + * Sets the color of the reflection background (deprecated) + * + * Value is an hexadecimal color, such as #FFFFFF + * + * Default value is #FFFFFF + * + * This setting is relevant only if {@link image_reflection_height} is set + * + * This setting is now deprecated in favor of {@link image_default_color} + * + * @access public + * @var string; + */ + var $image_reflection_color; + + /** + * Sets the initial opacity of the reflection + * + * Value is an integer between 0 (no opacity) and 100 (full opacity). + * The reflection will start from {@link image_reflection_opacity} and end up at 0 + * + * Default value is 60 + * + * This setting is relevant only if {@link image_reflection_height} is set + * + * @access public + * @var integer + */ + var $image_reflection_opacity; + + /** + * Flips the image vertically or horizontally + * + * Value is either 'h' or 'v', as in horizontal and vertical + * + * Default value is null (no flip) + * + * @access public + * @var string; + */ + var $image_flip; + + /** + * Rotates the image by increments of 45 degrees + * + * Value is either 90, 180 or 270 + * + * Default value is null (no rotation) + * + * @access public + * @var string; + */ + var $image_rotate; + + /** + * Crops an image + * + * Values are four dimensions, or two, or one (CSS style) + * They represent the amount cropped top, right, bottom and left. + * These values can either be in an array, or a space separated string. + * Each value can be in pixels (with or without 'px'), or percentage (of the source image) + * + * For instance, are valid: + *
    +     * $foo->image_crop = 20                  OR array(20);
    +     * $foo->image_crop = '20px'              OR array('20px');
    +     * $foo->image_crop = '20 40'             OR array('20', 40);
    +     * $foo->image_crop = '-20 25%'           OR array(-20, '25%');
    +     * $foo->image_crop = '20px 25%'          OR array('20px', '25%');
    +     * $foo->image_crop = '20% 25%'           OR array('20%', '25%');
    +     * $foo->image_crop = '20% 25% 10% 30%'   OR array('20%', '25%', '10%', '30%');
    +     * $foo->image_crop = '20px 25px 2px 2px' OR array('20px', '25%px', '2px', '2px');
    +     * $foo->image_crop = '20 25% 40px 10%'   OR array(20, '25%', '40px', '10%');
    +     * 
    + * + * If a value is negative, the image will be expanded, and the extra parts will be filled with black + * + * Default value is null (no cropping) + * + * @access public + * @var string OR array; + */ + var $image_crop; + + /** + * Crops an image, before an eventual resizing + * + * See {@link image_crop} for valid formats + * + * Default value is null (no cropping) + * + * @access public + * @var string OR array; + */ + var $image_precrop; + + /** + * Adds a bevel border on the image + * + * Value is a positive integer, representing the thickness of the bevel + * + * If the bevel colors are the same as the background, it makes a fade out effect + * + * Default value is null (no bevel) + * + * @access public + * @var integer + */ + var $image_bevel; + + /** + * Top and left bevel color + * + * Value is a color, in hexadecimal format + * This setting is used only if {@link image_bevel} is set + * + * Default value is #FFFFFF + * + * @access public + * @var string; + */ + var $image_bevel_color1; + + /** + * Right and bottom bevel color + * + * Value is a color, in hexadecimal format + * This setting is used only if {@link image_bevel} is set + * + * Default value is #000000 + * + * @access public + * @var string; + */ + var $image_bevel_color2; + + /** + * Adds a single-color border on the outer of the image + * + * Values are four dimensions, or two, or one (CSS style) + * They represent the border thickness top, right, bottom and left. + * These values can either be in an array, or a space separated string. + * Each value can be in pixels (with or without 'px'), or percentage (of the source image) + * + * See {@link image_crop} for valid formats + * + * If a value is negative, the image will be cropped. + * Note that the dimensions of the picture will be increased by the borders' thickness + * + * Default value is null (no border) + * + * @access public + * @var integer + */ + var $image_border; + + /** + * Border color + * + * Value is a color, in hexadecimal format. + * This setting is used only if {@link image_border} is set + * + * Default value is #FFFFFF + * + * @access public + * @var string; + */ + var $image_border_color; + + /** + * Sets the opacity for the borders + * + * Value is a percentage, as an integer between 0 (transparent) and 100 (opaque) + * + * Unless used with {@link image_border}, this setting has no effect + * + * Default value is 100 + * + * @access public + * @var integer + */ + var $image_border_opacity; + + /** + * Adds a fading-to-transparent border on the image + * + * Values are four dimensions, or two, or one (CSS style) + * They represent the border thickness top, right, bottom and left. + * These values can either be in an array, or a space separated string. + * Each value can be in pixels (with or without 'px'), or percentage (of the source image) + * + * See {@link image_crop} for valid formats + * + * Note that the dimensions of the picture will not be increased by the borders' thickness + * + * Default value is null (no border) + * + * @access public + * @var integer + */ + var $image_border_transparent; + + /** + * Adds a multi-color frame on the outer of the image + * + * Value is an integer. Two values are possible for now: + * 1 for flat border, meaning that the frame is mirrored horizontally and vertically + * 2 for crossed border, meaning that the frame will be inversed, as in a bevel effect + * + * The frame will be composed of colored lines set in {@link image_frame_colors} + * + * Note that the dimensions of the picture will be increased by the borders' thickness + * + * Default value is null (no frame) + * + * @access public + * @var integer + */ + var $image_frame; + + /** + * Sets the colors used to draw a frame + * + * Values is a list of n colors in hexadecimal format. + * These values can either be in an array, or a space separated string. + * + * The colors are listed in the following order: from the outset of the image to its center + * + * For instance, are valid: + *
    +     * $foo->image_frame_colors = '#FFFFFF #999999 #666666 #000000';
    +     * $foo->image_frame_colors = array('#FFFFFF', '#999999', '#666666', '#000000');
    +     * 
    + * + * This setting is used only if {@link image_frame} is set + * + * Default value is '#FFFFFF #999999 #666666 #000000' + * + * @access public + * @var string OR array; + */ + var $image_frame_colors; + + /** + * Sets the opacity for the frame + * + * Value is a percentage, as an integer between 0 (transparent) and 100 (opaque) + * + * Unless used with {@link image_frame}, this setting has no effect + * + * Default value is 100 + * + * @access public + * @var integer + */ + var $image_frame_opacity; + + /** + * Adds a watermark on the image + * + * Value is a local image filename, relative or absolute. GIF, JPG, BMP and PNG are supported, as well as PNG alpha. + * + * If set, this setting allow the use of all other settings starting with image_watermark_ + * + * Default value is null + * + * @access public + * @var string; + */ + var $image_watermark; + + /** + * Sets the watermarkposition within the image + * + * Value is one or two out of 'TBLR' (top, bottom, left, right) + * + * The positions are as following: TL T TR + * L R + * BL B BR + * + * Default value is null (centered, horizontal and vertical) + * + * Note that is {@link image_watermark_x} and {@link image_watermark_y} are used, this setting has no effect + * + * @access public + * @var string; + */ + var $image_watermark_position; + + /** + * Sets the watermark absolute X position within the image + * + * Value is in pixels, representing the distance between the top of the image and the watermark + * If a negative value is used, it will represent the distance between the bottom of the image and the watermark + * + * Default value is null (so {@link image_watermark_position} is used) + * + * @access public + * @var integer + */ + var $image_watermark_x; + + /** + * Sets the twatermark absolute Y position within the image + * + * Value is in pixels, representing the distance between the left of the image and the watermark + * If a negative value is used, it will represent the distance between the right of the image and the watermark + * + * Default value is null (so {@link image_watermark_position} is used) + * + * @access public + * @var integer + */ + var $image_watermark_y; + + /** + * Prevents the watermark to be resized up if it is smaller than the image + * + * If the watermark if smaller than the destination image, taking in account the desired watermark position + * then it will be resized up to fill in the image (minus the {@link image_watermark_x} or {@link image_watermark_y} values) + * + * If you don't want your watermark to be resized in any way, then + * set {@link image_watermark_no_zoom_in} and {@link image_watermark_no_zoom_out} to true + * If you want your watermark to be resized up or doan to fill in the image better, then + * set {@link image_watermark_no_zoom_in} and {@link image_watermark_no_zoom_out} to false + * + * Default value is true (so the watermark will not be resized up, which is the behaviour most people expect) + * + * @access public + * @var integer + */ + var $image_watermark_no_zoom_in; + + /** + * Prevents the watermark to be resized down if it is bigger than the image + * + * If the watermark if bigger than the destination image, taking in account the desired watermark position + * then it will be resized down to fit in the image (minus the {@link image_watermark_x} or {@link image_watermark_y} values) + * + * If you don't want your watermark to be resized in any way, then + * set {@link image_watermark_no_zoom_in} and {@link image_watermark_no_zoom_out} to true + * If you want your watermark to be resized up or doan to fill in the image better, then + * set {@link image_watermark_no_zoom_in} and {@link image_watermark_no_zoom_out} to false + * + * Default value is false (so the watermark may be shrinked to fit in the image) + * + * @access public + * @var integer + */ + var $image_watermark_no_zoom_out; + + /** + * List of MIME types per extension + * + * @access private + * @var array + */ + var $mime_types; + + /** + * Allowed MIME types + * + * Default is a selection of safe mime-types, but you might want to change it + * + * Simple wildcards are allowed, such as image/* or application/* + * If there is only one MIME type allowed, then it can be a string instead of an array + * + * @access public + * @var array OR string + */ + var $allowed; + + /** + * Forbidden MIME types + * + * Default is a selection of safe mime-types, but you might want to change it + * To only check for forbidden MIME types, and allow everything else, set {@link allowed} to array('* / *') without the spaces + * + * Simple wildcards are allowed, such as image/* or application/* + * If there is only one MIME type forbidden, then it can be a string instead of an array + * + * @access public + * @var array OR string + */ + var $forbidden; + + /** + * Array of translated error messages + * + * By default, the language is english (en_GB) + * Translations can be in separate files, in a lang/ subdirectory + * + * @access public + * @var array + */ + var $translation; + + /** + * Language selected for the translations + * + * By default, the language is english ("en_GB") + * + * @access public + * @var array + */ + var $language; + + /** + * Init or re-init all the processing variables to their default values + * + * This function is called in the constructor, and after each call of {@link process} + * + * @access private + */ + function init() { + + // overiddable variables + $this->file_new_name_body = null; // replace the name body + $this->file_name_body_add = null; // append to the name body + $this->file_name_body_pre = null; // prepend to the name body + $this->file_new_name_ext = null; // replace the file extension + $this->file_safe_name = true; // format safely the filename + $this->file_force_extension = true; // forces extension if there isn't one + $this->file_overwrite = false; // allows overwritting if the file already exists + $this->file_auto_rename = true; // auto-rename if the file already exists + $this->dir_auto_create = true; // auto-creates directory if missing + $this->dir_auto_chmod = true; // auto-chmod directory if not writeable + $this->dir_chmod = 0777; // default chmod to use + + $this->no_script = true; // turns scripts into test files + $this->mime_check = true; // checks the mime type against the allowed list + + // these are the different MIME detection methods. if one of these method doesn't work on your + // system, you can deactivate it here; just set it to false + $this->mime_fileinfo = true; // MIME detection with Fileinfo PECL extension + $this->mime_file = true; // MIME detection with UNIX file() command + $this->mime_magic = true; // MIME detection with mime_magic (mime_content_type()) + $this->mime_getimagesize = true; // MIME detection with getimagesize() + + // get the default max size from php.ini + $this->file_max_size_raw = trim(ini_get('upload_max_filesize')); + $this->file_max_size = $this->getsize($this->file_max_size_raw); + + $this->image_resize = false; // resize the image + $this->image_convert = ''; // convert. values :''; 'png'; 'jpeg'; 'gif'; 'bmp' + + $this->image_x = 150; + $this->image_y = 150; + $this->image_ratio = false; // keeps aspect ratio with x and y dimensions + $this->image_ratio_crop = false; // keeps aspect ratio with x and y dimensions, filling the space + $this->image_ratio_fill = false; // keeps aspect ratio with x and y dimensions, fitting the image in the space, and coloring the rest + $this->image_ratio_pixels = false; // keeps aspect ratio, calculating x and y so that the image is approx the set number of pixels + $this->image_ratio_no_zoom_in = false; + $this->image_ratio_no_zoom_out = false; + $this->image_ratio_x = false; // calculate the $image_x if true + $this->image_ratio_y = false; // calculate the $image_y if true + $this->png_compression = null; + $this->jpeg_quality = 85; + $this->jpeg_size = null; + $this->image_interlace = false; + $this->preserve_transparency = false; + $this->image_is_transparent = false; + $this->image_transparent_color = null; + $this->image_background_color = null; + $this->image_default_color = '#ffffff'; + $this->image_is_palette = false; + + $this->image_max_width = null; + $this->image_max_height = null; + $this->image_max_pixels = null; + $this->image_max_ratio = null; + $this->image_min_width = null; + $this->image_min_height = null; + $this->image_min_pixels = null; + $this->image_min_ratio = null; + + $this->image_brightness = null; + $this->image_contrast = null; + $this->image_opacity = null; + $this->image_threshold = null; + $this->image_tint_color = null; + $this->image_overlay_color = null; + $this->image_overlay_opacity = null; + $this->image_overlay_percent = null; + $this->image_negative = false; + $this->image_greyscale = false; + $this->image_pixelate = null; + $this->image_unsharp = false; + $this->image_unsharp_amount = 80; + $this->image_unsharp_radius = 0.5; + $this->image_unsharp_threshold = 1; + + $this->image_text = null; + $this->image_text_direction = null; + $this->image_text_color = '#FFFFFF'; + $this->image_text_opacity = 100; + $this->image_text_percent = 100; + $this->image_text_background = null; + $this->image_text_background_opacity = 100; + $this->image_text_background_percent = 100; + $this->image_text_font = 5; + $this->image_text_x = null; + $this->image_text_y = null; + $this->image_text_position = null; + $this->image_text_padding = 0; + $this->image_text_padding_x = null; + $this->image_text_padding_y = null; + $this->image_text_alignment = 'C'; + $this->image_text_line_spacing = 0; + + $this->image_reflection_height = null; + $this->image_reflection_space = 2; + $this->image_reflection_color = '#ffffff'; + $this->image_reflection_opacity = 60; + + $this->image_watermark = null; + $this->image_watermark_x = null; + $this->image_watermark_y = null; + $this->image_watermark_position = null; + $this->image_watermark_no_zoom_in = true; + $this->image_watermark_no_zoom_out = false; + + $this->image_flip = null; + $this->image_rotate = null; + $this->image_crop = null; + $this->image_precrop = null; + + $this->image_bevel = null; + $this->image_bevel_color1 = '#FFFFFF'; + $this->image_bevel_color2 = '#000000'; + $this->image_border = null; + $this->image_border_color = '#FFFFFF'; + $this->image_border_opacity = 100; + $this->image_border_transparent = null; + $this->image_frame = null; + $this->image_frame_colors = '#FFFFFF #999999 #666666 #000000'; + $this->image_frame_opacity = 100; + + $this->forbidden = array(); + $this->allowed = array( + 'application/arj', + 'application/excel', + 'application/gnutar', + 'application/mspowerpoint', + 'application/msword', + 'application/octet-stream', + 'application/onenote', + 'application/pdf', + 'application/plain', + 'application/postscript', + 'application/powerpoint', + 'application/rar', + 'application/rtf', + 'application/vnd.ms-excel', + 'application/vnd.ms-excel.addin.macroEnabled.12', + 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'application/vnd.ms-excel.sheet.macroEnabled.12', + 'application/vnd.ms-excel.template.macroEnabled.12', + 'application/vnd.ms-office', + 'application/vnd.ms-officetheme', + 'application/vnd.ms-powerpoint', + 'application/vnd.ms-powerpoint.addin.macroEnabled.12', + 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', + 'application/vnd.ms-powerpoint.slide.macroEnabled.12', + 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', + 'application/vnd.ms-powerpoint.template.macroEnabled.12', + 'application/vnd.ms-word', + 'application/vnd.ms-word.document.macroEnabled.12', + 'application/vnd.ms-word.template.macroEnabled.12', + 'application/vnd.oasis.opendocument.chart', + 'application/vnd.oasis.opendocument.database', + 'application/vnd.oasis.opendocument.formula', + 'application/vnd.oasis.opendocument.graphics', + 'application/vnd.oasis.opendocument.graphics-template', + 'application/vnd.oasis.opendocument.image', + 'application/vnd.oasis.opendocument.presentation', + 'application/vnd.oasis.opendocument.presentation-template', + 'application/vnd.oasis.opendocument.spreadsheet', + 'application/vnd.oasis.opendocument.spreadsheet-template', + 'application/vnd.oasis.opendocument.text', + 'application/vnd.oasis.opendocument.text-master', + 'application/vnd.oasis.opendocument.text-template', + 'application/vnd.oasis.opendocument.text-web', + 'application/vnd.openofficeorg.extension', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'application/vocaltec-media-file', + 'application/wordperfect', + 'application/x-bittorrent', + 'application/x-bzip', + 'application/x-bzip2', + 'application/x-compressed', + 'application/x-excel', + 'application/x-gzip', + 'application/x-latex', + 'application/x-midi', + 'application/xml', + 'application/x-msexcel', + 'application/x-rar', + 'application/x-rar-compressed', + 'application/x-rtf', + 'application/x-shockwave-flash', + 'application/x-sit', + 'application/x-stuffit', + 'application/x-troff-msvideo', + 'application/x-zip', + 'application/x-zip-compressed', + 'application/zip', + 'audio/*', + 'image/*', + 'multipart/x-gzip', + 'multipart/x-zip', + 'text/plain', + 'text/rtf', + 'text/richtext', + 'text/xml', + 'video/*' + ); + + $this->mime_types = array( + 'jpg' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpe' => 'image/jpeg', + 'gif' => 'image/gif', + 'png' => 'image/png', + 'bmp' => 'image/bmp', + 'flv' => 'video/x-flv', + 'js' => 'application/x-javascript', + 'json' => 'application/json', + 'tiff' => 'image/tiff', + 'css' => 'text/css', + 'xml' => 'application/xml', + 'doc' => 'application/msword', + 'docx' => 'application/msword', + 'xls' => 'application/vnd.ms-excel', + 'xlt' => 'application/vnd.ms-excel', + 'xlm' => 'application/vnd.ms-excel', + 'xld' => 'application/vnd.ms-excel', + 'xla' => 'application/vnd.ms-excel', + 'xlc' => 'application/vnd.ms-excel', + 'xlw' => 'application/vnd.ms-excel', + 'xll' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pps' => 'application/vnd.ms-powerpoint', + 'rtf' => 'application/rtf', + 'pdf' => 'application/pdf', + 'html' => 'text/html', + 'htm' => 'text/html', + 'php' => 'text/html', + 'txt' => 'text/plain', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'mp3' => 'audio/mpeg3', + 'wav' => 'audio/wav', + 'aiff' => 'audio/aiff', + 'aif' => 'audio/aiff', + 'avi' => 'video/msvideo', + 'wmv' => 'video/x-ms-wmv', + 'mov' => 'video/quicktime', + 'zip' => 'application/zip', + 'tar' => 'application/x-tar', + 'swf' => 'application/x-shockwave-flash', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'oxt' => 'application/vnd.openofficeorg.extension', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'docm' => 'application/vnd.ms-word.document.macroEnabled.12', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'dotm' => 'application/vnd.ms-word.template.macroEnabled.12', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12', + 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12', + 'thmx' => 'application/vnd.ms-officetheme', + 'onetoc' => 'application/onenote', + 'onetoc2' => 'application/onenote', + 'onetmp' => 'application/onenote', + 'onepkg' => 'application/onenote', + ); + + } + + /** + * Constructor. Checks if the file has been uploaded + * + * The constructor takes $_FILES['form_field'] array as argument + * where form_field is the form field name + * + * The constructor will check if the file has been uploaded in its temporary location, and + * accordingly will set {@link uploaded} (and {@link error} is an error occurred) + * + * If the file has been uploaded, the constructor will populate all the variables holding the upload + * information (none of the processing class variables are used here). + * You can have access to information about the file (name, size, MIME type...). + * + * + * Alternatively, you can set the first argument to be a local filename (string) + * This allows processing of a local file, as if the file was uploaded + * + * The optional second argument allows you to set the language for the error messages + * + * @access private + * @param array $file $_FILES['form_field'] + * or string $file Local filename + * @param string $lang Optional language code + */ + function upload($file, $lang = 'en_GB') { + + $this->version = '0.32'; + + $this->file_src_name = ''; + $this->file_src_name_body = ''; + $this->file_src_name_ext = ''; + $this->file_src_mime = ''; + $this->file_src_size = ''; + $this->file_src_error = ''; + $this->file_src_pathname = ''; + $this->file_src_temp = ''; + + $this->file_dst_path = ''; + $this->file_dst_name = ''; + $this->file_dst_name_body = ''; + $this->file_dst_name_ext = ''; + $this->file_dst_pathname = ''; + + $this->image_src_x = null; + $this->image_src_y = null; + $this->image_src_bits = null; + $this->image_src_type = null; + $this->image_src_pixels = null; + $this->image_dst_x = 0; + $this->image_dst_y = 0; + + $this->uploaded = true; + $this->no_upload_check = false; + $this->processed = true; + $this->error = ''; + $this->log = ''; + $this->allowed = array(); + $this->forbidden = array(); + $this->file_is_image = false; + $this->init(); + $info = null; + $mime_from_browser = null; + + // sets default language + $this->translation = array(); + $this->translation['file_error'] = 'File error. Please try again.'; + $this->translation['local_file_missing'] = 'Local file doesn\'t exist.'; + $this->translation['local_file_not_readable'] = 'Local file is not readable.'; + $this->translation['uploaded_too_big_ini'] = 'File upload error (the uploaded file exceeds the upload_max_filesize directive in php.ini).'; + $this->translation['uploaded_too_big_html'] = 'File upload error (the uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form).'; + $this->translation['uploaded_partial'] = 'File upload error (the uploaded file was only partially uploaded).'; + $this->translation['uploaded_missing'] = 'File upload error (no file was uploaded).'; + $this->translation['uploaded_no_tmp_dir'] = 'File upload error (missing a temporary folder).'; + $this->translation['uploaded_cant_write'] = 'File upload error (failed to write file to disk).'; + $this->translation['uploaded_err_extension'] = 'File upload error (file upload stopped by extension).'; + $this->translation['uploaded_unknown'] = 'File upload error (unknown error code).'; + $this->translation['try_again'] = 'File upload error. Please try again.'; + $this->translation['file_too_big'] = 'File too big.'; + $this->translation['no_mime'] = 'MIME type can\'t be detected.'; + $this->translation['incorrect_file'] = 'Incorrect type of file.'; + $this->translation['image_too_wide'] = 'Image too wide.'; + $this->translation['image_too_narrow'] = 'Image too narrow.'; + $this->translation['image_too_high'] = 'Image too tall.'; + $this->translation['image_too_short'] = 'Image too short.'; + $this->translation['ratio_too_high'] = 'Image ratio too high (image too wide).'; + $this->translation['ratio_too_low'] = 'Image ratio too low (image too high).'; + $this->translation['too_many_pixels'] = 'Image has too many pixels.'; + $this->translation['not_enough_pixels'] = 'Image has not enough pixels.'; + $this->translation['file_not_uploaded'] = 'File not uploaded. Can\'t carry on a process.'; + $this->translation['already_exists'] = '%s already exists. Please change the file name.'; + $this->translation['temp_file_missing'] = 'No correct temp source file. Can\'t carry on a process.'; + $this->translation['source_missing'] = 'No correct uploaded source file. Can\'t carry on a process.'; + $this->translation['destination_dir'] = 'Destination directory can\'t be created. Can\'t carry on a process.'; + $this->translation['destination_dir_missing'] = 'Destination directory doesn\'t exist. Can\'t carry on a process.'; + $this->translation['destination_path_not_dir'] = 'Destination path is not a directory. Can\'t carry on a process.'; + $this->translation['destination_dir_write'] = 'Destination directory can\'t be made writeable. Can\'t carry on a process.'; + $this->translation['destination_path_write'] = 'Destination path is not a writeable. Can\'t carry on a process.'; + $this->translation['temp_file'] = 'Can\'t create the temporary file. Can\'t carry on a process.'; + $this->translation['source_not_readable'] = 'Source file is not readable. Can\'t carry on a process.'; + $this->translation['no_create_support'] = 'No create from %s support.'; + $this->translation['create_error'] = 'Error in creating %s image from source.'; + $this->translation['source_invalid'] = 'Can\'t read image source. Not an image?.'; + $this->translation['gd_missing'] = 'GD doesn\'t seem to be present.'; + $this->translation['watermark_no_create_support'] = 'No create from %s support, can\'t read watermark.'; + $this->translation['watermark_create_error'] = 'No %s read support, can\'t create watermark.'; + $this->translation['watermark_invalid'] = 'Unknown image format, can\'t read watermark.'; + $this->translation['file_create'] = 'No %s create support.'; + $this->translation['no_conversion_type'] = 'No conversion type defined.'; + $this->translation['copy_failed'] = 'Error copying file on the server. copy() failed.'; + $this->translation['reading_failed'] = 'Error reading the file.'; + + // determines the language + $this->lang = $lang; + if ($this->lang != 'en_GB' && file_exists(dirname(__FILE__).'/lang') && file_exists(dirname(__FILE__).'/lang/class.upload.' . $lang . '.php')) { + $translation = null; + include(dirname(__FILE__).'/lang/class.upload.' . $lang . '.php'); + if (is_array($translation)) { + $this->translation = array_merge($this->translation, $translation); + } else { + $this->lang = 'en_GB'; + } + } + + + // determines the supported MIME types, and matching image format + $this->image_supported = array(); + if ($this->gdversion()) { + if (imagetypes() & IMG_GIF) { + $this->image_supported['image/gif'] = 'gif'; + } + if (imagetypes() & IMG_JPG) { + $this->image_supported['image/jpg'] = 'jpg'; + $this->image_supported['image/jpeg'] = 'jpg'; + $this->image_supported['image/pjpeg'] = 'jpg'; + } + if (imagetypes() & IMG_PNG) { + $this->image_supported['image/png'] = 'png'; + $this->image_supported['image/x-png'] = 'png'; + } + if (imagetypes() & IMG_WBMP) { + $this->image_supported['image/bmp'] = 'bmp'; + $this->image_supported['image/x-ms-bmp'] = 'bmp'; + $this->image_supported['image/x-windows-bmp'] = 'bmp'; + } + } + + // display some system information + if (empty($this->log)) { + $this->log .= 'system information
    '; + if (function_exists('ini_get_all')) { + $inis = ini_get_all(); + $open_basedir = (array_key_exists('open_basedir', $inis) && array_key_exists('local_value', $inis['open_basedir']) && !empty($inis['open_basedir']['local_value'])) ? $inis['open_basedir']['local_value'] : false; + } else { + $open_basedir = false; + } + $gd = $this->gdversion() ? $this->gdversion(true) : 'GD not present'; + $supported = trim((in_array('png', $this->image_supported) ? 'png' : '') . ' ' . (in_array('jpg', $this->image_supported) ? 'jpg' : '') . ' ' . (in_array('gif', $this->image_supported) ? 'gif' : '') . ' ' . (in_array('bmp', $this->image_supported) ? 'bmp' : '')); + $this->log .= '- class version : ' . $this->version . '
    '; + $this->log .= '- operating system : ' . PHP_OS . '
    '; + $this->log .= '- PHP version : ' . PHP_VERSION . '
    '; + $this->log .= '- GD version : ' . $gd . '
    '; + $this->log .= '- supported image types : ' . (!empty($supported) ? $supported : 'none') . '
    '; + $this->log .= '- open_basedir : ' . (!empty($open_basedir) ? $open_basedir : 'no restriction') . '
    '; + $this->log .= '- upload_max_filesize : ' . $this->file_max_size_raw . ' (' . $this->file_max_size . ' bytes)
    '; + $this->log .= '- language : ' . $this->lang . '
    '; + } + + if (!$file) { + $this->uploaded = false; + $this->error = $this->translate('file_error'); + } + + // check if we sent a local filename or a PHP stream rather than a $_FILE element + if (!is_array($file)) { + if (empty($file)) { + $this->uploaded = false; + $this->error = $this->translate('file_error'); + } else { + if (substr($file, 0, 4) == 'php:') { + // this is a local filename, i.e.not uploaded + $file = preg_replace('/^php:(.*)/i', '$1', $file); + if (!$file) $file = $_SERVER['HTTP_X_FILE_NAME']; + if (!$file) $file = 'unknown'; + $this->log .= '' . $this->translate("source is a PHP stream") . ' ' . $file . '
    '; + $this->no_upload_check = TRUE; + + $this->log .= '- this is a PHP stream, requires a temp file ... '; + $hash = $this->temp_dir() . md5($file . rand(1, 1000)); + if (file_put_contents($hash, file_get_contents('php://input'))) { + $this->file_src_pathname = $hash; + $this->log .= ' file created
    '; + $this->log .= '    temp file is: ' . $this->file_src_pathname . '
    '; + } else { + $this->log .= ' failed
    '; + $this->uploaded = false; + $this->error = $this->translate('temp_file'); + } + + if ($this->uploaded) { + $this->file_src_name = $file; + $this->log .= '- local file OK
    '; + preg_match('/\.([^\.]*$)/', $this->file_src_name, $extension); + if (is_array($extension) && sizeof($extension) > 0) { + $this->file_src_name_ext = strtolower($extension[1]); + $this->file_src_name_body = substr($this->file_src_name, 0, ((strlen($this->file_src_name) - strlen($this->file_src_name_ext)))-1); + } else { + $this->file_src_name_ext = ''; + $this->file_src_name_body = $this->file_src_name; + } + $this->file_src_size = (file_exists($file) ? filesize($file) : 0); + } + $this->file_src_error = 0; + + } else { + // this is a local filename, i.e.not uploaded + $this->log .= '' . $this->translate("source is a local file") . ' ' . $file . '
    '; + $this->no_upload_check = TRUE; + + if ($this->uploaded && !file_exists($file)) { + $this->uploaded = false; + $this->error = $this->translate('local_file_missing'); + } + + if ($this->uploaded && !is_readable($file)) { + $this->uploaded = false; + $this->error = $this->translate('local_file_not_readable'); + } + + if ($this->uploaded) { + $this->file_src_pathname = $file; + $this->file_src_name = basename($file); + $this->log .= '- local file OK
    '; + preg_match('/\.([^\.]*$)/', $this->file_src_name, $extension); + if (is_array($extension) && sizeof($extension) > 0) { + $this->file_src_name_ext = strtolower($extension[1]); + $this->file_src_name_body = substr($this->file_src_name, 0, ((strlen($this->file_src_name) - strlen($this->file_src_name_ext)))-1); + } else { + $this->file_src_name_ext = ''; + $this->file_src_name_body = $this->file_src_name; + } + $this->file_src_size = (file_exists($file) ? filesize($file) : 0); + } + $this->file_src_error = 0; + } + } + } else { + // this is an element from $_FILE, i.e. an uploaded file + $this->log .= 'source is an uploaded file
    '; + if ($this->uploaded) { + $this->file_src_error = trim($file['error']); + switch($this->file_src_error) { + case UPLOAD_ERR_OK: + // all is OK + $this->log .= '- upload OK
    '; + break; + case UPLOAD_ERR_INI_SIZE: + $this->uploaded = false; + $this->error = $this->translate('uploaded_too_big_ini'); + break; + case UPLOAD_ERR_FORM_SIZE: + $this->uploaded = false; + $this->error = $this->translate('uploaded_too_big_html'); + break; + case UPLOAD_ERR_PARTIAL: + $this->uploaded = false; + $this->error = $this->translate('uploaded_partial'); + break; + case UPLOAD_ERR_NO_FILE: + $this->uploaded = false; + $this->error = $this->translate('uploaded_missing'); + break; + case @UPLOAD_ERR_NO_TMP_DIR: + $this->uploaded = false; + $this->error = $this->translate('uploaded_no_tmp_dir'); + break; + case @UPLOAD_ERR_CANT_WRITE: + $this->uploaded = false; + $this->error = $this->translate('uploaded_cant_write'); + break; + case @UPLOAD_ERR_EXTENSION: + $this->uploaded = false; + $this->error = $this->translate('uploaded_err_extension'); + break; + default: + $this->uploaded = false; + $this->error = $this->translate('uploaded_unknown') . ' ('.$this->file_src_error.')'; + } + } + + if ($this->uploaded) { + $this->file_src_pathname = $file['tmp_name']; + $this->file_src_name = $file['name']; + if ($this->file_src_name == '') { + $this->uploaded = false; + $this->error = $this->translate('try_again'); + } + } + + if ($this->uploaded) { + $this->log .= '- file name OK
    '; + preg_match('/\.([^\.]*$)/', $this->file_src_name, $extension); + if (is_array($extension) && sizeof($extension) > 0) { + $this->file_src_name_ext = strtolower($extension[1]); + $this->file_src_name_body = substr($this->file_src_name, 0, ((strlen($this->file_src_name) - strlen($this->file_src_name_ext)))-1); + } else { + $this->file_src_name_ext = ''; + $this->file_src_name_body = $this->file_src_name; + } + $this->file_src_size = $file['size']; + $mime_from_browser = $file['type']; + } + } + + if ($this->uploaded) { + $this->log .= 'determining MIME type
    '; + $this->file_src_mime = null; + + // checks MIME type with Fileinfo PECL extension + if (!$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime) || strpos($this->file_src_mime, '/') === FALSE) { + if ($this->mime_fileinfo) { + $this->log .= '- Checking MIME type with Fileinfo PECL extension
    '; + if (function_exists('finfo_open')) { + $path = null; + if ($this->mime_fileinfo !== '') { + if ($this->mime_fileinfo === true) { + if (getenv('MAGIC') === FALSE) { + if (substr(PHP_OS, 0, 3) == 'WIN') { + $path = realpath(ini_get('extension_dir') . '/../') . 'extras/magic'; + $this->log .= '    MAGIC path defaults to ' . $path . '
    '; + } + } else { + $path = getenv('MAGIC'); + $this->log .= '    MAGIC path is set to ' . $path . ' from MAGIC variable
    '; + } + } else { + $path = $this->mime_fileinfo; + $this->log .= '    MAGIC path is set to ' . $path . '
    '; + } + } + if ($path) { + $f = @finfo_open(FILEINFO_MIME, $path); + } else { + $this->log .= '    MAGIC path will not be used
    '; + $f = @finfo_open(FILEINFO_MIME); + } + if (is_resource($f)) { + $mime = finfo_file($f, realpath($this->file_src_pathname)); + finfo_close($f); + $this->file_src_mime = $mime; + $this->log .= '    MIME type detected as ' . $this->file_src_mime . ' by Fileinfo PECL extension
    '; + if (preg_match("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", $this->file_src_mime)) { + $this->file_src_mime = preg_replace("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", '$1/$2', $this->file_src_mime); + $this->log .= '- MIME validated as ' . $this->file_src_mime . '
    '; + } else { + $this->file_src_mime = null; + } + } else { + $this->log .= '    Fileinfo PECL extension failed (finfo_open)
    '; + } + } elseif (@class_exists('finfo')) { + $f = new finfo( FILEINFO_MIME ); + if ($f) { + $this->file_src_mime = $f->file(realpath($this->file_src_pathname)); + $this->log .= '- MIME type detected as ' . $this->file_src_mime . ' by Fileinfo PECL extension
    '; + if (preg_match("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", $this->file_src_mime)) { + $this->file_src_mime = preg_replace("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", '$1/$2', $this->file_src_mime); + $this->log .= '- MIME validated as ' . $this->file_src_mime . '
    '; + } else { + $this->file_src_mime = null; + } + } else { + $this->log .= '    Fileinfo PECL extension failed (finfo)
    '; + } + } else { + $this->log .= '    Fileinfo PECL extension not available
    '; + } + } else { + $this->log .= '- Fileinfo PECL extension deactivated
    '; + } + } + + // checks MIME type with shell if unix access is authorized + if (!$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime) || strpos($this->file_src_mime, '/') === FALSE) { + if ($this->mime_file) { + $this->log .= '- Checking MIME type with UNIX file() command
    '; + if (substr(PHP_OS, 0, 3) != 'WIN') { + if (function_exists('exec') && function_exists('escapeshellarg') && !extension_loaded('suhosin')) { + if (strlen($mime = @exec("file -bi ".escapeshellarg($this->file_src_pathname))) != 0) { + $this->file_src_mime = trim($mime); + $this->log .= '    MIME type detected as ' . $this->file_src_mime . ' by UNIX file() command
    '; + if (preg_match("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", $this->file_src_mime)) { + $this->file_src_mime = preg_replace("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", '$1/$2', $this->file_src_mime); + $this->log .= '- MIME validated as ' . $this->file_src_mime . '
    '; + } else { + $this->file_src_mime = null; + } + } else { + $this->log .= '    UNIX file() command failed
    '; + } + } else { + $this->log .= '    PHP exec() function is disabled
    '; + } + } else { + $this->log .= '    UNIX file() command not availabled
    '; + } + } else { + $this->log .= '- UNIX file() command is deactivated
    '; + } + } + + // checks MIME type with mime_magic + if (!$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime) || strpos($this->file_src_mime, '/') === FALSE) { + if ($this->mime_magic) { + $this->log .= '- Checking MIME type with mime.magic file (mime_content_type())
    '; + if (function_exists('mime_content_type')) { + $this->file_src_mime = mime_content_type($this->file_src_pathname); + $this->log .= '    MIME type detected as ' . $this->file_src_mime . ' by mime_content_type()
    '; + if (preg_match("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", $this->file_src_mime)) { + $this->file_src_mime = preg_replace("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", '$1/$2', $this->file_src_mime); + $this->log .= '- MIME validated as ' . $this->file_src_mime . '
    '; + } else { + $this->file_src_mime = null; + } + } else { + $this->log .= '    mime_content_type() is not available
    '; + } + } else { + $this->log .= '- mime.magic file (mime_content_type()) is deactivated
    '; + } + } + + // checks MIME type with getimagesize() + if (!$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime) || strpos($this->file_src_mime, '/') === FALSE) { + if ($this->mime_getimagesize) { + $this->log .= '- Checking MIME type with getimagesize()
    '; + $info = getimagesize($this->file_src_pathname); + if (is_array($info) && array_key_exists('mime', $info)) { + $this->file_src_mime = trim($info['mime']); + if (empty($this->file_src_mime)) { + $this->log .= '    MIME empty, guessing from type
    '; + $mime = (is_array($info) && array_key_exists(2, $info) ? $info[2] : null); // 1 = GIF, 2 = JPG, 3 = PNG + $this->file_src_mime = ($mime==IMAGETYPE_GIF ? 'image/gif' : ($mime==IMAGETYPE_JPEG ? 'image/jpeg' : ($mime==IMAGETYPE_PNG ? 'image/png' : ($mime==IMAGETYPE_BMP ? 'image/bmp' : null)))); + } + $this->log .= '    MIME type detected as ' . $this->file_src_mime . ' by PHP getimagesize() function
    '; + if (preg_match("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", $this->file_src_mime)) { + $this->file_src_mime = preg_replace("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", '$1/$2', $this->file_src_mime); + $this->log .= '- MIME validated as ' . $this->file_src_mime . '
    '; + } else { + $this->file_src_mime = null; + } + } else { + $this->log .= '    getimagesize() failed
    '; + } + } else { + $this->log .= '- getimagesize() is deactivated
    '; + } + } + + // default to MIME from browser (or Flash) + if (!empty($mime_from_browser) && !$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime)) { + $this->file_src_mime =$mime_from_browser; + $this->log .= '- MIME type detected as ' . $this->file_src_mime . ' by browser
    '; + if (preg_match("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", $this->file_src_mime)) { + $this->file_src_mime = preg_replace("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", '$1/$2', $this->file_src_mime); + $this->log .= '- MIME validated as ' . $this->file_src_mime . '
    '; + } else { + $this->file_src_mime = null; + } + } + + // we need to work some magic if we upload via Flash + if ($this->file_src_mime == 'application/octet-stream' || !$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime) || strpos($this->file_src_mime, '/') === FALSE) { + if ($this->file_src_mime == 'application/octet-stream') $this->log .= '- Flash may be rewriting MIME as application/octet-stream
    '; + $this->log .= '- Try to guess MIME type from file extension (' . $this->file_src_name_ext . '): '; + if (array_key_exists($this->file_src_name_ext, $this->mime_types)) $this->file_src_mime = $this->mime_types[$this->file_src_name_ext]; + if ($this->file_src_mime == 'application/octet-stream') { + $this->log .= 'doesn\'t look like anything known
    '; + } else { + $this->log .= 'MIME type set to ' . $this->file_src_mime . '
    '; + } + } + + if (!$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime) || strpos($this->file_src_mime, '/') === FALSE) { + $this->log .= '- MIME type couldn\'t be detected! (' . (string) $this->file_src_mime . ')
    '; + } + + // determine whether the file is an image + if ($this->file_src_mime && is_string($this->file_src_mime) && !empty($this->file_src_mime) && array_key_exists($this->file_src_mime, $this->image_supported)) { + $this->file_is_image = true; + $this->image_src_type = $this->image_supported[$this->file_src_mime]; + } + + // if the file is an image, we gather some useful data + if ($this->file_is_image) { + if ($h = fopen($this->file_src_pathname, 'r')) { + fclose($h); + $info = getimagesize($this->file_src_pathname); + if (is_array($info)) { + $this->image_src_x = $info[0]; + $this->image_src_y = $info[1]; + $this->image_dst_x = $this->image_src_x; + $this->image_dst_y = $this->image_src_y; + $this->image_src_pixels = $this->image_src_x * $this->image_src_y; + $this->image_src_bits = array_key_exists('bits', $info) ? $info['bits'] : null; + } else { + $this->file_is_image = false; + $this->uploaded = false; + $this->log .= '- can\'t retrieve image information, image may have been tampered with
    '; + $this->error = $this->translate('source_invalid'); + } + } else { + $this->log .= '- can\'t read source file directly. open_basedir restriction in place?
    '; + } + } + + $this->log .= 'source variables
    '; + $this->log .= '- You can use all these before calling process()
    '; + $this->log .= '    file_src_name : ' . $this->file_src_name . '
    '; + $this->log .= '    file_src_name_body : ' . $this->file_src_name_body . '
    '; + $this->log .= '    file_src_name_ext : ' . $this->file_src_name_ext . '
    '; + $this->log .= '    file_src_pathname : ' . $this->file_src_pathname . '
    '; + $this->log .= '    file_src_mime : ' . $this->file_src_mime . '
    '; + $this->log .= '    file_src_size : ' . $this->file_src_size . ' (max= ' . $this->file_max_size . ')
    '; + $this->log .= '    file_src_error : ' . $this->file_src_error . '
    '; + + if ($this->file_is_image) { + $this->log .= '- source file is an image
    '; + $this->log .= '    image_src_x : ' . $this->image_src_x . '
    '; + $this->log .= '    image_src_y : ' . $this->image_src_y . '
    '; + $this->log .= '    image_src_pixels : ' . $this->image_src_pixels . '
    '; + $this->log .= '    image_src_type : ' . $this->image_src_type . '
    '; + $this->log .= '    image_src_bits : ' . $this->image_src_bits . '
    '; + } + } + + } + + /** + * Returns the version of GD + * + * @access public + * @param boolean $full Optional flag to get precise version + * @return float GD version + */ + function gdversion($full = false) { + static $gd_version = null; + static $gd_full_version = null; + if ($gd_version === null) { + if (function_exists('gd_info')) { + $gd = gd_info(); + $gd = $gd["GD Version"]; + $regex = "/([\d\.]+)/i"; + } else { + ob_start(); + phpinfo(8); + $gd = ob_get_contents(); + ob_end_clean(); + $regex = "/\bgd\s+version\b[^\d\n\r]+?([\d\.]+)/i"; + } + if (preg_match($regex, $gd, $m)) { + $gd_full_version = (string) $m[1]; + $gd_version = (float) $m[1]; + } else { + $gd_full_version = 'none'; + $gd_version = 0; + } + } + if ($full) { + return $gd_full_version; + } else { + return $gd_version; + } + } + + /** + * Creates directories recursively + * + * @access private + * @param string $path Path to create + * @param integer $mode Optional permissions + * @return boolean Success + */ + function rmkdir($path, $mode = 0777) { + return is_dir($path) || ( $this->rmkdir(dirname($path), $mode) && $this->_mkdir($path, $mode) ); + } + + /** + * Creates directory + * + * @access private + * @param string $path Path to create + * @param integer $mode Optional permissions + * @return boolean Success + */ + function _mkdir($path, $mode = 0777) { + $old = umask(0); + $res = @mkdir($path, $mode); + umask($old); + return $res; + } + + /** + * Translate error messages + * + * @access private + * @param string $str Message to translate + * @param array $tokens Optional token values + * @return string Translated string + */ + function translate($str, $tokens = array()) { + if (array_key_exists($str, $this->translation)) $str = $this->translation[$str]; + if (is_array($tokens) && sizeof($tokens) > 0) $str = vsprintf($str, $tokens); + return $str; + } + + /** + * Returns the temp directory + * + * @access private + * @return string Temp directory string + */ + function temp_dir() { + $dir = ''; + if (function_exists('sys_get_temp_dir')) $dir = sys_get_temp_dir(); + if (!$dir && $tmp=getenv('TMP')) $dir = $tmp; + if (!$dir && $tmp=getenv('TEMP')) $dir = $tmp; + if (!$dir && $tmp=getenv('TMPDIR')) $dir = $tmp; + if (!$dir) { + $tmp = tempnam(__FILE__,''); + if (file_exists($tmp)) { + unlink($tmp); + $dir = dirname($tmp); + } + } + if (!$dir) return ''; + $slash = (strtolower(substr(PHP_OS, 0, 3)) === 'win' ? '\\' : '/'); + if (substr($dir, -1) != $slash) $dir = $dir . $slash; + return $dir; + } + + /** + * Decodes colors + * + * @access private + * @param string $color Color string + * @return array RGB colors + */ + function getcolors($color) { + $color = str_replace('#', '', $color); + if (strlen($color) == 3) $color = str_repeat(substr($color, 0, 1), 2) . str_repeat(substr($color, 1, 1), 2) . str_repeat(substr($color, 2, 1), 2); + $r = sscanf($color, "%2x%2x%2x"); + $red = (is_array($r) && array_key_exists(0, $r) && is_numeric($r[0]) ? $r[0] : 0); + $green = (is_array($r) && array_key_exists(1, $r) && is_numeric($r[1]) ? $r[1] : 0); + $blue = (is_array($r) && array_key_exists(2, $r) && is_numeric($r[2]) ? $r[2] : 0); + return array($red, $green, $blue); + } + + /** + * Decodes sizes + * + * @access private + * @param string $size Size in bytes, or shorthand byte options + * @return integer Size in bytes + */ + function getsize($size) { + $last = strtolower($size{strlen($size)-1}); + switch($last) { + case 'g': + $size *= 1024; + case 'm': + $size *= 1024; + case 'k': + $size *= 1024; + } + return $size; + } + + /** + * Decodes offsets + * + * @access private + * @param misc $offsets Offsets, as an integer, a string or an array + * @param integer $x Reference picture width + * @param integer $y Reference picture height + * @param boolean $round Round offsets before returning them + * @param boolean $negative Allow negative offsets to be returned + * @return array Array of four offsets (TRBL) + */ + function getoffsets($offsets, $x, $y, $round = true, $negative = true) { + if (!is_array($offsets)) $offsets = explode(' ', $offsets); + if (sizeof($offsets) == 4) { + $ct = $offsets[0]; $cr = $offsets[1]; $cb = $offsets[2]; $cl = $offsets[3]; + } else if (sizeof($offsets) == 2) { + $ct = $offsets[0]; $cr = $offsets[1]; $cb = $offsets[0]; $cl = $offsets[1]; + } else { + $ct = $offsets[0]; $cr = $offsets[0]; $cb = $offsets[0]; $cl = $offsets[0]; + } + if (strpos($ct, '%')>0) $ct = $y * (str_replace('%','',$ct) / 100); + if (strpos($cr, '%')>0) $cr = $x * (str_replace('%','',$cr) / 100); + if (strpos($cb, '%')>0) $cb = $y * (str_replace('%','',$cb) / 100); + if (strpos($cl, '%')>0) $cl = $x * (str_replace('%','',$cl) / 100); + if (strpos($ct, 'px')>0) $ct = str_replace('px','',$ct); + if (strpos($cr, 'px')>0) $cr = str_replace('px','',$cr); + if (strpos($cb, 'px')>0) $cb = str_replace('px','',$cb); + if (strpos($cl, 'px')>0) $cl = str_replace('px','',$cl); + $ct = (int) $ct; $cr = (int) $cr; $cb = (int) $cb; $cl = (int) $cl; + if ($round) { + $ct = round($ct); + $cr = round($cr); + $cb = round($cb); + $cl = round($cl); + } + if (!$negative) { + if ($ct < 0) $ct = 0; + if ($cr < 0) $cr = 0; + if ($cb < 0) $cb = 0; + if ($cl < 0) $cl = 0; + } + return array($ct, $cr, $cb, $cl); + } + + /** + * Creates a container image + * + * @access private + * @param integer $x Width + * @param integer $y Height + * @param boolean $fill Optional flag to draw the background color or not + * @param boolean $trsp Optional flag to set the background to be transparent + * @return resource Container image + */ + function imagecreatenew($x, $y, $fill = true, $trsp = false) { + if ($x < 1) $x = 1; if ($y < 1) $y = 1; + if ($this->gdversion() >= 2 && !$this->image_is_palette) { + // create a true color image + $dst_im = imagecreatetruecolor($x, $y); + // this preserves transparency in PNGs, in true color + if (empty($this->image_background_color) || $trsp) { + imagealphablending($dst_im, false ); + imagefilledrectangle($dst_im, 0, 0, $x, $y, imagecolorallocatealpha($dst_im, 0, 0, 0, 127)); + } + } else { + // creates a palette image + $dst_im = imagecreate($x, $y); + // preserves transparency for palette images, if the original image has transparency + if (($fill && $this->image_is_transparent && empty($this->image_background_color)) || $trsp) { + imagefilledrectangle($dst_im, 0, 0, $x, $y, $this->image_transparent_color); + imagecolortransparent($dst_im, $this->image_transparent_color); + } + } + // fills with background color if any is set + if ($fill && !empty($this->image_background_color) && !$trsp) { + list($red, $green, $blue) = $this->getcolors($this->image_background_color); + $background_color = imagecolorallocate($dst_im, $red, $green, $blue); + imagefilledrectangle($dst_im, 0, 0, $x, $y, $background_color); + } + return $dst_im; + } + + + /** + * Transfers an image from the container to the destination image + * + * @access private + * @param resource $src_im Container image + * @param resource $dst_im Destination image + * @return resource Destination image + */ + function imagetransfer($src_im, $dst_im) { + if (is_resource($dst_im)) imagedestroy($dst_im); + $dst_im = & $src_im; + return $dst_im; + } + + /** + * Merges two images + * + * If the output format is PNG, then we do it pixel per pixel to retain the alpha channel + * + * @access private + * @param resource $dst_img Destination image + * @param resource $src_img Overlay image + * @param int $dst_x x-coordinate of destination point + * @param int $dst_y y-coordinate of destination point + * @param int $src_x x-coordinate of source point + * @param int $src_y y-coordinate of source point + * @param int $src_w Source width + * @param int $src_h Source height + * @param int $pct Optional percentage of the overlay, between 0 and 100 (default: 100) + * @return resource Destination image + */ + function imagecopymergealpha(&$dst_im, &$src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct = 0) { + $dst_x = (int) $dst_x; + $dst_y = (int) $dst_y; + $src_x = (int) $src_x; + $src_y = (int) $src_y; + $src_w = (int) $src_w; + $src_h = (int) $src_h; + $pct = (int) $pct; + $dst_w = imagesx($dst_im); + $dst_h = imagesy($dst_im); + + for ($y = $src_y; $y < $src_h; $y++) { + for ($x = $src_x; $x < $src_w; $x++) { + + if ($x + $dst_x >= 0 && $x + $dst_x < $dst_w && $x + $src_x >= 0 && $x + $src_x < $src_w + && $y + $dst_y >= 0 && $y + $dst_y < $dst_h && $y + $src_y >= 0 && $y + $src_y < $src_h) { + + $dst_pixel = imagecolorsforindex($dst_im, imagecolorat($dst_im, $x + $dst_x, $y + $dst_y)); + $src_pixel = imagecolorsforindex($src_im, imagecolorat($src_im, $x + $src_x, $y + $src_y)); + + $src_alpha = 1 - ($src_pixel['alpha'] / 127); + $dst_alpha = 1 - ($dst_pixel['alpha'] / 127); + $opacity = $src_alpha * $pct / 100; + if ($dst_alpha >= $opacity) $alpha = $dst_alpha; + if ($dst_alpha < $opacity) $alpha = $opacity; + if ($alpha > 1) $alpha = 1; + + if ($opacity > 0) { + $dst_red = round(( ($dst_pixel['red'] * $dst_alpha * (1 - $opacity)) ) ); + $dst_green = round(( ($dst_pixel['green'] * $dst_alpha * (1 - $opacity)) ) ); + $dst_blue = round(( ($dst_pixel['blue'] * $dst_alpha * (1 - $opacity)) ) ); + $src_red = round((($src_pixel['red'] * $opacity)) ); + $src_green = round((($src_pixel['green'] * $opacity)) ); + $src_blue = round((($src_pixel['blue'] * $opacity)) ); + $red = round(($dst_red + $src_red ) / ($dst_alpha * (1 - $opacity) + $opacity)); + $green = round(($dst_green + $src_green) / ($dst_alpha * (1 - $opacity) + $opacity)); + $blue = round(($dst_blue + $src_blue ) / ($dst_alpha * (1 - $opacity) + $opacity)); + if ($red > 255) $red = 255; + if ($green > 255) $green = 255; + if ($blue > 255) $blue = 255; + $alpha = round((1 - $alpha) * 127); + $color = imagecolorallocatealpha($dst_im, $red, $green, $blue, $alpha); + imagesetpixel($dst_im, $x + $dst_x, $y + $dst_y, $color); + } + } + } + } + return true; + } + + + + /** + * Actually uploads the file, and act on it according to the set processing class variables + * + * This function copies the uploaded file to the given location, eventually performing actions on it. + * Typically, you can call {@link process} several times for the same file, + * for instance to create a resized image and a thumbnail of the same file. + * The original uploaded file remains intact in its temporary location, so you can use {@link process} several times. + * You will be able to delete the uploaded file with {@link clean} when you have finished all your {@link process} calls. + * + * According to the processing class variables set in the calling file, the file can be renamed, + * and if it is an image, can be resized or converted. + * + * When the processing is completed, and the file copied to its new location, the + * processing class variables will be reset to their default value. + * This allows you to set new properties, and perform another {@link process} on the same uploaded file + * + * If the function is called with a null or empty argument, then it will return the content of the picture + * + * It will set {@link processed} (and {@link error} is an error occurred) + * + * @access public + * @param string $server_path Optional path location of the uploaded file, with an ending slash + * @return string Optional content of the image + */ + function process($server_path = null) { + $this->error = ''; + $this->processed = true; + $return_mode = false; + $return_content = null; + + // clean up dst variables + $this->file_dst_path = ''; + $this->file_dst_pathname = ''; + $this->file_dst_name = ''; + $this->file_dst_name_body = ''; + $this->file_dst_name_ext = ''; + + // clean up some parameters + $this->file_max_size = $this->getsize($this->file_max_size); + $this->jpeg_size = $this->getsize($this->jpeg_size); + // some parameters are being deprecated, and replaced with others + if (is_null($this->image_overlay_opacity)) $this->image_overlay_opacity = $this->image_overlay_percent; + if ($this->image_text_opacity == 100) $this->image_text_opacity = $this->image_text_percent; + if ($this->image_text_background_opacity == 100) $this->image_text_background_opacity = $this->image_text_background_percent; + + // copy some variables as we need to keep them clean + $file_src_name = $this->file_src_name; + $file_src_name_body = $this->file_src_name_body; + $file_src_name_ext = $this->file_src_name_ext; + + if (!$this->uploaded) { + $this->error = $this->translate('file_not_uploaded'); + $this->processed = false; + } + + if ($this->processed) { + if (empty($server_path) || is_null($server_path)) { + $this->log .= 'process file and return the content
    '; + $return_mode = true; + } else { + if(strtolower(substr(PHP_OS, 0, 3)) === 'win') { + if (substr($server_path, -1, 1) != '\\') $server_path = $server_path . '\\'; + } else { + if (substr($server_path, -1, 1) != '/') $server_path = $server_path . '/'; + } + $this->log .= 'process file to ' . $server_path . '
    '; + } + } + + if ($this->processed) { + // checks file max size + if ($this->file_src_size > $this->file_max_size) { + $this->processed = false; + $this->error = $this->translate('file_too_big'); + } else { + $this->log .= '- file size OK
    '; + } + } + + if ($this->processed) { + // if we have an image without extension, set it + if ($this->file_force_extension && $this->file_is_image && !$this->file_src_name_ext) $file_src_name_ext = $this->image_src_type; + // turn dangerous scripts into text files + if ($this->no_script) { + // if the file has no extension, we try to guess it from the MIME type + if ($this->file_force_extension && empty($file_src_name_ext)) { + if ($key = array_search($this->file_src_mime, $this->mime_types)) { + $file_src_name_ext = $key; + $file_src_name = $file_src_name_body . '.' . $file_src_name_ext; + $this->log .= '- file renamed as ' . $file_src_name_body . '.' . $file_src_name_ext . '!
    '; + } + } + // if the file is text based, or has a dangerous extension, we rename it as .txt + if ((((substr($this->file_src_mime, 0, 5) == 'text/' && $this->file_src_mime != 'text/rtf') || strpos($this->file_src_mime, 'javascript') !== false) && (substr($file_src_name, -4) != '.txt')) + || preg_match('/\.(php|php5|php4|php3|phtml|pl|py|cgi|asp|js)$/i', $this->file_src_name) + || $this->file_force_extension && empty($file_src_name_ext)) { + $this->file_src_mime = 'text/plain'; + if ($this->file_src_name_ext) $file_src_name_body = $file_src_name_body . '.' . $this->file_src_name_ext; + $file_src_name_ext = 'txt'; + $file_src_name = $file_src_name_body . '.' . $file_src_name_ext; + $this->log .= '- script renamed as ' . $file_src_name_body . '.' . $file_src_name_ext . '!
    '; + } + } + + if ($this->mime_check && empty($this->file_src_mime)) { + $this->processed = false; + $this->error = $this->translate('no_mime'); + } else if ($this->mime_check && !empty($this->file_src_mime) && strpos($this->file_src_mime, '/') !== false) { + list($m1, $m2) = explode('/', $this->file_src_mime); + $allowed = false; + // check wether the mime type is allowed + if (!is_array($this->allowed)) $this->allowed = array($this->allowed); + foreach($this->allowed as $k => $v) { + list($v1, $v2) = explode('/', $v); + if (($v1 == '*' && $v2 == '*') || ($v1 == $m1 && ($v2 == $m2 || $v2 == '*'))) { + $allowed = true; + break; + } + } + // check wether the mime type is forbidden + if (!is_array($this->forbidden)) $this->forbidden = array($this->forbidden); + foreach($this->forbidden as $k => $v) { + list($v1, $v2) = explode('/', $v); + if (($v1 == '*' && $v2 == '*') || ($v1 == $m1 && ($v2 == $m2 || $v2 == '*'))) { + $allowed = false; + break; + } + } + if (!$allowed) { + $this->processed = false; + $this->error = $this->translate('incorrect_file'); + } else { + $this->log .= '- file mime OK : ' . $this->file_src_mime . '
    '; + } + } else { + $this->log .= '- file mime (not checked) : ' . $this->file_src_mime . '
    '; + } + + // if the file is an image, we can check on its dimensions + // these checks are not available if open_basedir restrictions are in place + if ($this->file_is_image) { + if (is_numeric($this->image_src_x) && is_numeric($this->image_src_y)) { + $ratio = $this->image_src_x / $this->image_src_y; + if (!is_null($this->image_max_width) && $this->image_src_x > $this->image_max_width) { + $this->processed = false; + $this->error = $this->translate('image_too_wide'); + } + if (!is_null($this->image_min_width) && $this->image_src_x < $this->image_min_width) { + $this->processed = false; + $this->error = $this->translate('image_too_narrow'); + } + if (!is_null($this->image_max_height) && $this->image_src_y > $this->image_max_height) { + $this->processed = false; + $this->error = $this->translate('image_too_high'); + } + if (!is_null($this->image_min_height) && $this->image_src_y < $this->image_min_height) { + $this->processed = false; + $this->error = $this->translate('image_too_short'); + } + if (!is_null($this->image_max_ratio) && $ratio > $this->image_max_ratio) { + $this->processed = false; + $this->error = $this->translate('ratio_too_high'); + } + if (!is_null($this->image_min_ratio) && $ratio < $this->image_min_ratio) { + $this->processed = false; + $this->error = $this->translate('ratio_too_low'); + } + if (!is_null($this->image_max_pixels) && $this->image_src_pixels > $this->image_max_pixels) { + $this->processed = false; + $this->error = $this->translate('too_many_pixels'); + } + if (!is_null($this->image_min_pixels) && $this->image_src_pixels < $this->image_min_pixels) { + $this->processed = false; + $this->error = $this->translate('not_enough_pixels'); + } + } else { + $this->log .= '- no image properties available, can\'t enforce dimension checks : ' . $this->file_src_mime . '
    '; + } + } + } + + if ($this->processed) { + $this->file_dst_path = $server_path; + + // repopulate dst variables from src + $this->file_dst_name = $file_src_name; + $this->file_dst_name_body = $file_src_name_body; + $this->file_dst_name_ext = $file_src_name_ext; + if ($this->file_overwrite) $this->file_auto_rename = false; + + if ($this->image_convert && $this->file_is_image) { // if we convert as an image + if ($this->file_src_name_ext) $this->file_dst_name_ext = $this->image_convert; + $this->log .= '- new file name ext : ' . $this->image_convert . '
    '; + } + if (!is_null($this->file_new_name_body)) { // rename file body + $this->file_dst_name_body = $this->file_new_name_body; + $this->log .= '- new file name body : ' . $this->file_new_name_body . '
    '; + } + if (!is_null($this->file_new_name_ext)) { // rename file ext + $this->file_dst_name_ext = $this->file_new_name_ext; + $this->log .= '- new file name ext : ' . $this->file_new_name_ext . '
    '; + } + if (!is_null($this->file_name_body_add)) { // append a string to the name + $this->file_dst_name_body = $this->file_dst_name_body . $this->file_name_body_add; + $this->log .= '- file name body append : ' . $this->file_name_body_add . '
    '; + } + if (!is_null($this->file_name_body_pre)) { // prepend a string to the name + $this->file_dst_name_body = $this->file_name_body_pre . $this->file_dst_name_body; + $this->log .= '- file name body prepend : ' . $this->file_name_body_pre . '
    '; + } + if ($this->file_safe_name) { // formats the name + $this->file_dst_name_body = utf8_encode(strtr(utf8_decode($this->file_dst_name_body), utf8_decode('ŠŽšžŸÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÑÒÓÔÕÖØÙÚÛÜÝàáâãäåçèéêëìíîïñòóôõöøùúûüýÿ'), 'SZszYAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy')); + $this->file_dst_name_body = strtr($this->file_dst_name_body, array('Þ' => 'TH', 'þ' => 'th', 'Ð' => 'DH', 'ð' => 'dh', 'ß' => 'ss', 'Œ' => 'OE', 'œ' => 'oe', 'Æ' => 'AE', 'æ' => 'ae', 'µ' => 'u')); + $this->file_dst_name_body = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $this->file_dst_name_body); + $this->log .= '- file name safe format
    '; + } + + $this->log .= '- destination variables
    '; + if (empty($this->file_dst_path) || is_null($this->file_dst_path)) { + $this->log .= '    file_dst_path : n/a
    '; + } else { + $this->log .= '    file_dst_path : ' . $this->file_dst_path . '
    '; + } + $this->log .= '    file_dst_name_body : ' . $this->file_dst_name_body . '
    '; + $this->log .= '    file_dst_name_ext : ' . $this->file_dst_name_ext . '
    '; + + // do we do some image manipulation? + $image_manipulation = ($this->file_is_image && ( + $this->image_resize + || $this->image_convert != '' + || is_numeric($this->image_brightness) + || is_numeric($this->image_contrast) + || is_numeric($this->image_opacity) + || is_numeric($this->image_threshold) + || !empty($this->image_tint_color) + || !empty($this->image_overlay_color) + || $this->image_pixelate + || $this->image_unsharp + || !empty($this->image_text) + || $this->image_greyscale + || $this->image_negative + || !empty($this->image_watermark) + || is_numeric($this->image_rotate) + || is_numeric($this->jpeg_size) + || !empty($this->image_flip) + || !empty($this->image_crop) + || !empty($this->image_precrop) + || !empty($this->image_border) + || !empty($this->image_border_transparent) + || $this->image_frame > 0 + || $this->image_bevel > 0 + || $this->image_reflection_height)); + + // set the destination file name + $this->file_dst_name = $this->file_dst_name_body . (!empty($this->file_dst_name_ext) ? '.' . $this->file_dst_name_ext : ''); + + if (!$return_mode) { + if (!$this->file_auto_rename) { + $this->log .= '- no auto_rename if same filename exists
    '; + $this->file_dst_pathname = $this->file_dst_path . $this->file_dst_name; + } else { + $this->log .= '- checking for auto_rename
    '; + $this->file_dst_pathname = $this->file_dst_path . $this->file_dst_name; + $body = $this->file_dst_name_body; + $ext = ''; + // if we have changed the extension, then we add our increment before + if ($file_src_name_ext != $this->file_src_name_ext) { + if (substr($this->file_dst_name_body, -1 - strlen($this->file_src_name_ext)) == '.' . $this->file_src_name_ext) { + $body = substr($this->file_dst_name_body, 0, strlen($this->file_dst_name_body) - 1 - strlen($this->file_src_name_ext)); + $ext = '.' . $this->file_src_name_ext; + } + } + $cpt = 1; + while (@file_exists($this->file_dst_pathname)) { + $this->file_dst_name_body = $body . '_' . $cpt . $ext; + $this->file_dst_name = $this->file_dst_name_body . (!empty($this->file_dst_name_ext) ? '.' . $this->file_dst_name_ext : ''); + $cpt++; + $this->file_dst_pathname = $this->file_dst_path . $this->file_dst_name; + } + if ($cpt>1) $this->log .= '    auto_rename to ' . $this->file_dst_name . '
    '; + } + + $this->log .= '- destination file details
    '; + $this->log .= '    file_dst_name : ' . $this->file_dst_name . '
    '; + $this->log .= '    file_dst_pathname : ' . $this->file_dst_pathname . '
    '; + + if ($this->file_overwrite) { + $this->log .= '- no overwrite checking
    '; + } else { + if (@file_exists($this->file_dst_pathname)) { + $this->processed = false; + $this->error = $this->translate('already_exists', array($this->file_dst_name)); + } else { + $this->log .= '- ' . $this->file_dst_name . ' doesn\'t exist already
    '; + } + } + } + } + + if ($this->processed) { + // if we have already moved the uploaded file, we use the temporary copy as source file, and check if it exists + if (!empty($this->file_src_temp)) { + $this->log .= '- use the temp file instead of the original file since it is a second process
    '; + $this->file_src_pathname = $this->file_src_temp; + if (!file_exists($this->file_src_pathname)) { + $this->processed = false; + $this->error = $this->translate('temp_file_missing'); + } + // if we haven't a temp file, and that we do check on uploads, we use is_uploaded_file() + } else if (!$this->no_upload_check) { + if (!is_uploaded_file($this->file_src_pathname)) { + $this->processed = false; + $this->error = $this->translate('source_missing'); + } + // otherwise, if we don't check on uploaded files (local file for instance), we use file_exists() + } else { + if (!file_exists($this->file_src_pathname)) { + $this->processed = false; + $this->error = $this->translate('source_missing'); + } + } + + // checks if the destination directory exists, and attempt to create it + if (!$return_mode) { + if ($this->processed && !file_exists($this->file_dst_path)) { + if ($this->dir_auto_create) { + $this->log .= '- ' . $this->file_dst_path . ' doesn\'t exist. Attempting creation:'; + if (!$this->rmkdir($this->file_dst_path, $this->dir_chmod)) { + $this->log .= ' failed
    '; + $this->processed = false; + $this->error = $this->translate('destination_dir'); + } else { + $this->log .= ' success
    '; + } + } else { + $this->error = $this->translate('destination_dir_missing'); + } + } + + if ($this->processed && !is_dir($this->file_dst_path)) { + $this->processed = false; + $this->error = $this->translate('destination_path_not_dir'); + } + + // checks if the destination directory is writeable, and attempt to make it writeable + $hash = md5($this->file_dst_name_body . rand(1, 1000)); + if ($this->processed && !($f = @fopen($this->file_dst_path . $hash . (!empty($this->file_dst_name_ext) ? '.' . $this->file_dst_name_ext : ''), 'a+'))) { + if ($this->dir_auto_chmod) { + $this->log .= '- ' . $this->file_dst_path . ' is not writeable. Attempting chmod:'; + if (!@chmod($this->file_dst_path, $this->dir_chmod)) { + $this->log .= ' failed
    '; + $this->processed = false; + $this->error = $this->translate('destination_dir_write'); + } else { + $this->log .= ' success
    '; + if (!($f = @fopen($this->file_dst_path . $hash . (!empty($this->file_dst_name_ext) ? '.' . $this->file_dst_name_ext : ''), 'a+'))) { // we re-check + $this->processed = false; + $this->error = $this->translate('destination_dir_write'); + } else { + @fclose($f); + } + } + } else { + $this->processed = false; + $this->error = $this->translate('destination_path_write'); + } + } else { + if ($this->processed) @fclose($f); + @unlink($this->file_dst_path . $hash . (!empty($this->file_dst_name_ext) ? '.' . $this->file_dst_name_ext : '')); + } + + + // if we have an uploaded file, and if it is the first process, and if we can't access the file directly (open_basedir restriction) + // then we create a temp file that will be used as the source file in subsequent processes + // the third condition is there to check if the file is not accessible *directly* (it already has positively gone through is_uploaded_file(), so it exists) + if (!$this->no_upload_check && empty($this->file_src_temp) && !@file_exists($this->file_src_pathname)) { + $this->log .= '- attempting to use a temp file:'; + $hash = md5($this->file_dst_name_body . rand(1, 1000)); + if (move_uploaded_file($this->file_src_pathname, $this->file_dst_path . $hash . (!empty($this->file_dst_name_ext) ? '.' . $this->file_dst_name_ext : ''))) { + $this->file_src_pathname = $this->file_dst_path . $hash . (!empty($this->file_dst_name_ext) ? '.' . $this->file_dst_name_ext : ''); + $this->file_src_temp = $this->file_src_pathname; + $this->log .= ' file created
    '; + $this->log .= '    temp file is: ' . $this->file_src_temp . '
    '; + } else { + $this->log .= ' failed
    '; + $this->processed = false; + $this->error = $this->translate('temp_file'); + } + } + } + } + + if ($this->processed) { + + // we do a quick check to ensure the file is really an image + // we can do this only now, as it would have failed before in case of open_basedir + if ($image_manipulation && !@getimagesize($this->file_src_pathname)) { + $this->log .= '- the file is not an image!
    '; + $image_manipulation = false; + } + + if ($image_manipulation) { + + // make sure GD doesn't complain too much + ini_set("gd.jpeg_ignore_warning", 1); + + // checks if the source file is readable + if ($this->processed && !($f = @fopen($this->file_src_pathname, 'r'))) { + $this->processed = false; + $this->error = $this->translate('source_not_readable'); + } else { + @fclose($f); + } + + // we now do all the image manipulations + $this->log .= '- image resizing or conversion wanted
    '; + if ($this->gdversion()) { + switch($this->image_src_type) { + case 'jpg': + if (!function_exists('imagecreatefromjpeg')) { + $this->processed = false; + $this->error = $this->translate('no_create_support', array('JPEG')); + } else { + $image_src = @imagecreatefromjpeg($this->file_src_pathname); + if (!$image_src) { + $this->processed = false; + $this->error = $this->translate('create_error', array('JPEG')); + } else { + $this->log .= '- source image is JPEG
    '; + } + } + break; + case 'png': + if (!function_exists('imagecreatefrompng')) { + $this->processed = false; + $this->error = $this->translate('no_create_support', array('PNG')); + } else { + $image_src = @imagecreatefrompng($this->file_src_pathname); + if (!$image_src) { + $this->processed = false; + $this->error = $this->translate('create_error', array('PNG')); + } else { + $this->log .= '- source image is PNG
    '; + } + } + break; + case 'gif': + if (!function_exists('imagecreatefromgif')) { + $this->processed = false; + $this->error = $this->translate('no_create_support', array('GIF')); + } else { + $image_src = @imagecreatefromgif($this->file_src_pathname); + if (!$image_src) { + $this->processed = false; + $this->error = $this->translate('create_error', array('GIF')); + } else { + $this->log .= '- source image is GIF
    '; + } + } + break; + case 'bmp': + if (!method_exists($this, 'imagecreatefrombmp')) { + $this->processed = false; + $this->error = $this->translate('no_create_support', array('BMP')); + } else { + $image_src = @$this->imagecreatefrombmp($this->file_src_pathname); + if (!$image_src) { + $this->processed = false; + $this->error = $this->translate('create_error', array('BMP')); + } else { + $this->log .= '- source image is BMP
    '; + } + } + break; + default: + $this->processed = false; + $this->error = $this->translate('source_invalid'); + } + } else { + $this->processed = false; + $this->error = $this->translate('gd_missing'); + } + + if ($this->processed && $image_src) { + + // we have to set image_convert if it is not already + if (empty($this->image_convert)) { + $this->log .= '- setting destination file type to ' . $this->image_src_type . '
    '; + $this->image_convert = $this->image_src_type; + } + + if (!in_array($this->image_convert, $this->image_supported)) { + $this->image_convert = 'jpg'; + } + + // we set the default color to be the background color if we don't output in a transparent format + if ($this->image_convert != 'png' && $this->image_convert != 'gif' && !empty($this->image_default_color) && empty($this->image_background_color)) $this->image_background_color = $this->image_default_color; + if (!empty($this->image_background_color)) $this->image_default_color = $this->image_background_color; + if (empty($this->image_default_color)) $this->image_default_color = '#FFFFFF'; + + $this->image_src_x = imagesx($image_src); + $this->image_src_y = imagesy($image_src); + $gd_version = $this->gdversion(); + $ratio_crop = null; + + if (!imageistruecolor($image_src)) { // $this->image_src_type == 'gif' + $this->log .= '- image is detected as having a palette
    '; + $this->image_is_palette = true; + $this->image_transparent_color = imagecolortransparent($image_src); + if ($this->image_transparent_color >= 0 && imagecolorstotal($image_src) > $this->image_transparent_color) { + $this->image_is_transparent = true; + $this->log .= '    palette image is detected as transparent
    '; + } + // if the image has a palette (GIF), we convert it to true color, preserving transparency + $this->log .= '    convert palette image to true color
    '; + $true_color = imagecreatetruecolor($this->image_src_x, $this->image_src_y); + imagealphablending($true_color, false); + imagesavealpha($true_color, true); + for ($x = 0; $x < $this->image_src_x; $x++) { + for ($y = 0; $y < $this->image_src_y; $y++) { + if ($this->image_transparent_color >= 0 && imagecolorat($image_src, $x, $y) == $this->image_transparent_color) { + imagesetpixel($true_color, $x, $y, 127 << 24); + } else { + $rgb = imagecolorsforindex($image_src, imagecolorat($image_src, $x, $y)); + imagesetpixel($true_color, $x, $y, ($rgb['alpha'] << 24) | ($rgb['red'] << 16) | ($rgb['green'] << 8) | $rgb['blue']); + } + } + } + $image_src = $this->imagetransfer($true_color, $image_src); + imagealphablending($image_src, false); + imagesavealpha($image_src, true); + $this->image_is_palette = false; + } + + + $image_dst = & $image_src; + + // pre-crop image, before resizing + if ((!empty($this->image_precrop))) { + list($ct, $cr, $cb, $cl) = $this->getoffsets($this->image_precrop, $this->image_src_x, $this->image_src_y, true, true); + $this->log .= '- pre-crop image : ' . $ct . ' ' . $cr . ' ' . $cb . ' ' . $cl . '
    '; + $this->image_src_x = $this->image_src_x - $cl - $cr; + $this->image_src_y = $this->image_src_y - $ct - $cb; + if ($this->image_src_x < 1) $this->image_src_x = 1; + if ($this->image_src_y < 1) $this->image_src_y = 1; + $tmp = $this->imagecreatenew($this->image_src_x, $this->image_src_y); + + // we copy the image into the recieving image + imagecopy($tmp, $image_dst, 0, 0, $cl, $ct, $this->image_src_x, $this->image_src_y); + + // if we crop with negative margins, we have to make sure the extra bits are the right color, or transparent + if ($ct < 0 || $cr < 0 || $cb < 0 || $cl < 0 ) { + // use the background color if present + if (!empty($this->image_background_color)) { + list($red, $green, $blue) = $this->getcolors($this->image_background_color); + $fill = imagecolorallocate($tmp, $red, $green, $blue); + } else { + $fill = imagecolorallocatealpha($tmp, 0, 0, 0, 127); + } + // fills eventual negative margins + if ($ct < 0) imagefilledrectangle($tmp, 0, 0, $this->image_src_x, -$ct, $fill); + if ($cr < 0) imagefilledrectangle($tmp, $this->image_src_x + $cr, 0, $this->image_src_x, $this->image_src_y, $fill); + if ($cb < 0) imagefilledrectangle($tmp, 0, $this->image_src_y + $cb, $this->image_src_x, $this->image_src_y, $fill); + if ($cl < 0) imagefilledrectangle($tmp, 0, 0, -$cl, $this->image_src_y, $fill); + } + + // we transfert tmp into image_dst + $image_dst = $this->imagetransfer($tmp, $image_dst); + } + + // resize image (and move image_src_x, image_src_y dimensions into image_dst_x, image_dst_y) + if ($this->image_resize) { + $this->log .= '- resizing...
    '; + + if ($this->image_ratio_x) { + $this->log .= '    calculate x size
    '; + $this->image_dst_x = round(($this->image_src_x * $this->image_y) / $this->image_src_y); + $this->image_dst_y = $this->image_y; + } else if ($this->image_ratio_y) { + $this->log .= '    calculate y size
    '; + $this->image_dst_x = $this->image_x; + $this->image_dst_y = round(($this->image_src_y * $this->image_x) / $this->image_src_x); + } else if (is_numeric($this->image_ratio_pixels)) { + $this->log .= '    calculate x/y size to match a number of pixels
    '; + $pixels = $this->image_src_y * $this->image_src_x; + $diff = sqrt($this->image_ratio_pixels / $pixels); + $this->image_dst_x = round($this->image_src_x * $diff); + $this->image_dst_y = round($this->image_src_y * $diff); + } else if ($this->image_ratio || $this->image_ratio_crop || $this->image_ratio_fill || $this->image_ratio_no_zoom_in || $this->image_ratio_no_zoom_out) { + $this->log .= '    check x/y sizes
    '; + if ((!$this->image_ratio_no_zoom_in && !$this->image_ratio_no_zoom_out) + || ($this->image_ratio_no_zoom_in && ($this->image_src_x > $this->image_x || $this->image_src_y > $this->image_y)) + || ($this->image_ratio_no_zoom_out && $this->image_src_x < $this->image_x && $this->image_src_y < $this->image_y)) { + $this->image_dst_x = $this->image_x; + $this->image_dst_y = $this->image_y; + if ($this->image_ratio_crop) { + if (!is_string($this->image_ratio_crop)) $this->image_ratio_crop = ''; + $this->image_ratio_crop = strtolower($this->image_ratio_crop); + if (($this->image_src_x/$this->image_x) > ($this->image_src_y/$this->image_y)) { + $this->image_dst_y = $this->image_y; + $this->image_dst_x = intval($this->image_src_x*($this->image_y / $this->image_src_y)); + $ratio_crop = array(); + $ratio_crop['x'] = $this->image_dst_x - $this->image_x; + if (strpos($this->image_ratio_crop, 'l') !== false) { + $ratio_crop['l'] = 0; + $ratio_crop['r'] = $ratio_crop['x']; + } else if (strpos($this->image_ratio_crop, 'r') !== false) { + $ratio_crop['l'] = $ratio_crop['x']; + $ratio_crop['r'] = 0; + } else { + $ratio_crop['l'] = round($ratio_crop['x']/2); + $ratio_crop['r'] = $ratio_crop['x'] - $ratio_crop['l']; + } + $this->log .= '    ratio_crop_x : ' . $ratio_crop['x'] . ' (' . $ratio_crop['l'] . ';' . $ratio_crop['r'] . ')
    '; + if (is_null($this->image_crop)) $this->image_crop = array(0, 0, 0, 0); + } else { + $this->image_dst_x = $this->image_x; + $this->image_dst_y = intval($this->image_src_y*($this->image_x / $this->image_src_x)); + $ratio_crop = array(); + $ratio_crop['y'] = $this->image_dst_y - $this->image_y; + if (strpos($this->image_ratio_crop, 't') !== false) { + $ratio_crop['t'] = 0; + $ratio_crop['b'] = $ratio_crop['y']; + } else if (strpos($this->image_ratio_crop, 'b') !== false) { + $ratio_crop['t'] = $ratio_crop['y']; + $ratio_crop['b'] = 0; + } else { + $ratio_crop['t'] = round($ratio_crop['y']/2); + $ratio_crop['b'] = $ratio_crop['y'] - $ratio_crop['t']; + } + $this->log .= '    ratio_crop_y : ' . $ratio_crop['y'] . ' (' . $ratio_crop['t'] . ';' . $ratio_crop['b'] . ')
    '; + if (is_null($this->image_crop)) $this->image_crop = array(0, 0, 0, 0); + } + } else if ($this->image_ratio_fill) { + if (!is_string($this->image_ratio_fill)) $this->image_ratio_fill = ''; + $this->image_ratio_fill = strtolower($this->image_ratio_fill); + if (($this->image_src_x/$this->image_x) < ($this->image_src_y/$this->image_y)) { + $this->image_dst_y = $this->image_y; + $this->image_dst_x = intval($this->image_src_x*($this->image_y / $this->image_src_y)); + $ratio_crop = array(); + $ratio_crop['x'] = $this->image_dst_x - $this->image_x; + if (strpos($this->image_ratio_fill, 'l') !== false) { + $ratio_crop['l'] = 0; + $ratio_crop['r'] = $ratio_crop['x']; + } else if (strpos($this->image_ratio_fill, 'r') !== false) { + $ratio_crop['l'] = $ratio_crop['x']; + $ratio_crop['r'] = 0; + } else { + $ratio_crop['l'] = round($ratio_crop['x']/2); + $ratio_crop['r'] = $ratio_crop['x'] - $ratio_crop['l']; + } + $this->log .= '    ratio_fill_x : ' . $ratio_crop['x'] . ' (' . $ratio_crop['l'] . ';' . $ratio_crop['r'] . ')
    '; + if (is_null($this->image_crop)) $this->image_crop = array(0, 0, 0, 0); + } else { + $this->image_dst_x = $this->image_x; + $this->image_dst_y = intval($this->image_src_y*($this->image_x / $this->image_src_x)); + $ratio_crop = array(); + $ratio_crop['y'] = $this->image_dst_y - $this->image_y; + if (strpos($this->image_ratio_fill, 't') !== false) { + $ratio_crop['t'] = 0; + $ratio_crop['b'] = $ratio_crop['y']; + } else if (strpos($this->image_ratio_fill, 'b') !== false) { + $ratio_crop['t'] = $ratio_crop['y']; + $ratio_crop['b'] = 0; + } else { + $ratio_crop['t'] = round($ratio_crop['y']/2); + $ratio_crop['b'] = $ratio_crop['y'] - $ratio_crop['t']; + } + $this->log .= '    ratio_fill_y : ' . $ratio_crop['y'] . ' (' . $ratio_crop['t'] . ';' . $ratio_crop['b'] . ')
    '; + if (is_null($this->image_crop)) $this->image_crop = array(0, 0, 0, 0); + } + } else { + if (($this->image_src_x/$this->image_x) > ($this->image_src_y/$this->image_y)) { + $this->image_dst_x = $this->image_x; + $this->image_dst_y = intval($this->image_src_y*($this->image_x / $this->image_src_x)); + } else { + $this->image_dst_y = $this->image_y; + $this->image_dst_x = intval($this->image_src_x*($this->image_y / $this->image_src_y)); + } + } + } else { + $this->log .= '    doesn\'t calculate x/y sizes
    '; + $this->image_dst_x = $this->image_src_x; + $this->image_dst_y = $this->image_src_y; + } + } else { + $this->log .= '    use plain sizes
    '; + $this->image_dst_x = $this->image_x; + $this->image_dst_y = $this->image_y; + } + + if ($this->image_dst_x < 1) $this->image_dst_x = 1; + if ($this->image_dst_y < 1) $this->image_dst_y = 1; + $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y); + + if ($gd_version >= 2) { + $res = imagecopyresampled($tmp, $image_src, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y, $this->image_src_x, $this->image_src_y); + } else { + $res = imagecopyresized($tmp, $image_src, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y, $this->image_src_x, $this->image_src_y); + } + + $this->log .= '    resized image object created
    '; + $this->log .= '    image_src_x y : ' . $this->image_src_x . ' x ' . $this->image_src_y . '
    '; + $this->log .= '    image_dst_x y : ' . $this->image_dst_x . ' x ' . $this->image_dst_y . '
    '; + // we transfert tmp into image_dst + $image_dst = $this->imagetransfer($tmp, $image_dst); + + } else { + $this->image_dst_x = $this->image_src_x; + $this->image_dst_y = $this->image_src_y; + } + + // crop image (and also crops if image_ratio_crop is used) + if ((!empty($this->image_crop) || !is_null($ratio_crop))) { + list($ct, $cr, $cb, $cl) = $this->getoffsets($this->image_crop, $this->image_dst_x, $this->image_dst_y, true, true); + // we adjust the cropping if we use image_ratio_crop + if (!is_null($ratio_crop)) { + if (array_key_exists('t', $ratio_crop)) $ct += $ratio_crop['t']; + if (array_key_exists('r', $ratio_crop)) $cr += $ratio_crop['r']; + if (array_key_exists('b', $ratio_crop)) $cb += $ratio_crop['b']; + if (array_key_exists('l', $ratio_crop)) $cl += $ratio_crop['l']; + } + $this->log .= '- crop image : ' . $ct . ' ' . $cr . ' ' . $cb . ' ' . $cl . '
    '; + $this->image_dst_x = $this->image_dst_x - $cl - $cr; + $this->image_dst_y = $this->image_dst_y - $ct - $cb; + if ($this->image_dst_x < 1) $this->image_dst_x = 1; + if ($this->image_dst_y < 1) $this->image_dst_y = 1; + $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y); + + // we copy the image into the recieving image + imagecopy($tmp, $image_dst, 0, 0, $cl, $ct, $this->image_dst_x, $this->image_dst_y); + + // if we crop with negative margins, we have to make sure the extra bits are the right color, or transparent + if ($ct < 0 || $cr < 0 || $cb < 0 || $cl < 0 ) { + // use the background color if present + if (!empty($this->image_background_color)) { + list($red, $green, $blue) = $this->getcolors($this->image_background_color); + $fill = imagecolorallocate($tmp, $red, $green, $blue); + } else { + $fill = imagecolorallocatealpha($tmp, 0, 0, 0, 127); + } + // fills eventual negative margins + if ($ct < 0) imagefilledrectangle($tmp, 0, 0, $this->image_dst_x, -$ct-1, $fill); + if ($cr < 0) imagefilledrectangle($tmp, $this->image_dst_x + $cr, 0, $this->image_dst_x, $this->image_dst_y, $fill); + if ($cb < 0) imagefilledrectangle($tmp, 0, $this->image_dst_y + $cb, $this->image_dst_x, $this->image_dst_y, $fill); + if ($cl < 0) imagefilledrectangle($tmp, 0, 0, -$cl-1, $this->image_dst_y, $fill); + } + + // we transfert tmp into image_dst + $image_dst = $this->imagetransfer($tmp, $image_dst); + } + + // flip image + if ($gd_version >= 2 && !empty($this->image_flip)) { + $this->image_flip = strtolower($this->image_flip); + $this->log .= '- flip image : ' . $this->image_flip . '
    '; + $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y); + for ($x = 0; $x < $this->image_dst_x; $x++) { + for ($y = 0; $y < $this->image_dst_y; $y++){ + if (strpos($this->image_flip, 'v') !== false) { + imagecopy($tmp, $image_dst, $this->image_dst_x - $x - 1, $y, $x, $y, 1, 1); + } else { + imagecopy($tmp, $image_dst, $x, $this->image_dst_y - $y - 1, $x, $y, 1, 1); + } + } + } + // we transfert tmp into image_dst + $image_dst = $this->imagetransfer($tmp, $image_dst); + } + + // rotate image + if ($gd_version >= 2 && is_numeric($this->image_rotate)) { + if (!in_array($this->image_rotate, array(0, 90, 180, 270))) $this->image_rotate = 0; + if ($this->image_rotate != 0) { + if ($this->image_rotate == 90 || $this->image_rotate == 270) { + $tmp = $this->imagecreatenew($this->image_dst_y, $this->image_dst_x); + } else { + $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y); + } + $this->log .= '- rotate image : ' . $this->image_rotate . '
    '; + for ($x = 0; $x < $this->image_dst_x; $x++) { + for ($y = 0; $y < $this->image_dst_y; $y++){ + if ($this->image_rotate == 90) { + imagecopy($tmp, $image_dst, $y, $x, $x, $this->image_dst_y - $y - 1, 1, 1); + } else if ($this->image_rotate == 180) { + imagecopy($tmp, $image_dst, $x, $y, $this->image_dst_x - $x - 1, $this->image_dst_y - $y - 1, 1, 1); + } else if ($this->image_rotate == 270) { + imagecopy($tmp, $image_dst, $y, $x, $this->image_dst_x - $x - 1, $y, 1, 1); + } else { + imagecopy($tmp, $image_dst, $x, $y, $x, $y, 1, 1); + } + } + } + if ($this->image_rotate == 90 || $this->image_rotate == 270) { + $t = $this->image_dst_y; + $this->image_dst_y = $this->image_dst_x; + $this->image_dst_x = $t; + } + // we transfert tmp into image_dst + $image_dst = $this->imagetransfer($tmp, $image_dst); + } + } + + // pixelate image + if ((is_numeric($this->image_pixelate) && $this->image_pixelate > 0)) { + $this->log .= '- pixelate image (' . $this->image_pixelate . 'px)
    '; + $filter = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y); + if ($gd_version >= 2) { + imagecopyresampled($filter, $image_dst, 0, 0, 0, 0, round($this->image_dst_x / $this->image_pixelate), round($this->image_dst_y / $this->image_pixelate), $this->image_dst_x, $this->image_dst_y); + imagecopyresampled($image_dst, $filter, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y, round($this->image_dst_x / $this->image_pixelate), round($this->image_dst_y / $this->image_pixelate)); + } else { + imagecopyresized($filter, $image_dst, 0, 0, 0, 0, round($this->image_dst_x / $this->image_pixelate), round($this->image_dst_y / $this->image_pixelate), $this->image_dst_x, $this->image_dst_y); + imagecopyresized($image_dst, $filter, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y, round($this->image_dst_x / $this->image_pixelate), round($this->image_dst_y / $this->image_pixelate)); + } + imagedestroy($filter); + } + + // unsharp mask + if ($gd_version >= 2 && $this->image_unsharp && is_numeric($this->image_unsharp_amount) && is_numeric($this->image_unsharp_radius) && is_numeric($this->image_unsharp_threshold)) { + // Unsharp Mask for PHP - version 2.1.1 + // Unsharp mask algorithm by Torstein Hønsi 2003-07. + // Used with permission + // Modified to support alpha transparency + if ($this->image_unsharp_amount > 500) $this->image_unsharp_amount = 500; + $this->image_unsharp_amount = $this->image_unsharp_amount * 0.016; + if ($this->image_unsharp_radius > 50) $this->image_unsharp_radius = 50; + $this->image_unsharp_radius = $this->image_unsharp_radius * 2; + if ($this->image_unsharp_threshold > 255) $this->image_unsharp_threshold = 255; + $this->image_unsharp_radius = abs(round($this->image_unsharp_radius)); + if ($this->image_unsharp_radius != 0) { + $this->image_dst_x = imagesx($image_dst); $this->image_dst_y = imagesy($image_dst); + $canvas = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y, false, true); + $blur = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y, false, true); + if (function_exists('imageconvolution')) { // PHP >= 5.1 + $matrix = array(array( 1, 2, 1 ), array( 2, 4, 2 ), array( 1, 2, 1 )); + imagecopy($blur, $image_dst, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y); + imageconvolution($blur, $matrix, 16, 0); + } else { + for ($i = 0; $i < $this->image_unsharp_radius; $i++) { + imagecopy($blur, $image_dst, 0, 0, 1, 0, $this->image_dst_x - 1, $this->image_dst_y); // left + $this->imagecopymergealpha($blur, $image_dst, 1, 0, 0, 0, $this->image_dst_x, $this->image_dst_y, 50); // right + $this->imagecopymergealpha($blur, $image_dst, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y, 50); // center + imagecopy($canvas, $blur, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y); + $this->imagecopymergealpha($blur, $canvas, 0, 0, 0, 1, $this->image_dst_x, $this->image_dst_y - 1, 33.33333 ); // up + $this->imagecopymergealpha($blur, $canvas, 0, 1, 0, 0, $this->image_dst_x, $this->image_dst_y, 25); // down + } + } + $p_new = array(); + if($this->image_unsharp_threshold>0) { + for ($x = 0; $x < $this->image_dst_x-1; $x++) { + for ($y = 0; $y < $this->image_dst_y; $y++) { + $p_orig = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $p_blur = imagecolorsforindex($blur, imagecolorat($blur, $x, $y)); + $p_new['red'] = (abs($p_orig['red'] - $p_blur['red']) >= $this->image_unsharp_threshold) ? max(0, min(255, ($this->image_unsharp_amount * ($p_orig['red'] - $p_blur['red'])) + $p_orig['red'])) : $p_orig['red']; + $p_new['green'] = (abs($p_orig['green'] - $p_blur['green']) >= $this->image_unsharp_threshold) ? max(0, min(255, ($this->image_unsharp_amount * ($p_orig['green'] - $p_blur['green'])) + $p_orig['green'])) : $p_orig['green']; + $p_new['blue'] = (abs($p_orig['blue'] - $p_blur['blue']) >= $this->image_unsharp_threshold) ? max(0, min(255, ($this->image_unsharp_amount * ($p_orig['blue'] - $p_blur['blue'])) + $p_orig['blue'])) : $p_orig['blue']; + if (($p_orig['red'] != $p_new['red']) || ($p_orig['green'] != $p_new['green']) || ($p_orig['blue'] != $p_new['blue'])) { + $color = imagecolorallocatealpha($image_dst, $p_new['red'], $p_new['green'], $p_new['blue'], $p_orig['alpha']); + imagesetpixel($image_dst, $x, $y, $color); + } + } + } + } else { + for ($x = 0; $x < $this->image_dst_x; $x++) { + for ($y = 0; $y < $this->image_dst_y; $y++) { + $p_orig = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $p_blur = imagecolorsforindex($blur, imagecolorat($blur, $x, $y)); + $p_new['red'] = ($this->image_unsharp_amount * ($p_orig['red'] - $p_blur['red'])) + $p_orig['red']; + if ($p_new['red']>255) { $p_new['red']=255; } elseif ($p_new['red']<0) { $p_new['red']=0; } + $p_new['green'] = ($this->image_unsharp_amount * ($p_orig['green'] - $p_blur['green'])) + $p_orig['green']; + if ($p_new['green']>255) { $p_new['green']=255; } elseif ($p_new['green']<0) { $p_new['green']=0; } + $p_new['blue'] = ($this->image_unsharp_amount * ($p_orig['blue'] - $p_blur['blue'])) + $p_orig['blue']; + if ($p_new['blue']>255) { $p_new['blue']=255; } elseif ($p_new['blue']<0) { $p_new['blue']=0; } + $color = imagecolorallocatealpha($image_dst, $p_new['red'], $p_new['green'], $p_new['blue'], $p_orig['alpha']); + imagesetpixel($image_dst, $x, $y, $color); + } + } + } + imagedestroy($canvas); + imagedestroy($blur); + } + } + + // add color overlay + if ($gd_version >= 2 && (is_numeric($this->image_overlay_opacity) && $this->image_overlay_opacity > 0 && !empty($this->image_overlay_color))) { + $this->log .= '- apply color overlay
    '; + list($red, $green, $blue) = $this->getcolors($this->image_overlay_color); + $filter = imagecreatetruecolor($this->image_dst_x, $this->image_dst_y); + $color = imagecolorallocate($filter, $red, $green, $blue); + imagefilledrectangle($filter, 0, 0, $this->image_dst_x, $this->image_dst_y, $color); + $this->imagecopymergealpha($image_dst, $filter, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y, $this->image_overlay_opacity); + imagedestroy($filter); + } + + // add brightness, contrast and tint, turns to greyscale and inverts colors + if ($gd_version >= 2 && ($this->image_negative || $this->image_greyscale || is_numeric($this->image_threshold)|| is_numeric($this->image_brightness) || is_numeric($this->image_contrast) || !empty($this->image_tint_color))) { + $this->log .= '- apply tint, light, contrast correction, negative, greyscale and threshold
    '; + if (!empty($this->image_tint_color)) list($tint_red, $tint_green, $tint_blue) = $this->getcolors($this->image_tint_color); + //imagealphablending($image_dst, true); + for($y=0; $y < $this->image_dst_y; $y++) { + for($x=0; $x < $this->image_dst_x; $x++) { + if ($this->image_greyscale) { + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $r = $g = $b = round((0.2125 * $pixel['red']) + (0.7154 * $pixel['green']) + (0.0721 * $pixel['blue'])); + $color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']); + imagesetpixel($image_dst, $x, $y, $color); + unset($color); unset($pixel); + } + if (is_numeric($this->image_threshold)) { + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $c = (round($pixel['red'] + $pixel['green'] + $pixel['blue']) / 3) - 127; + $r = $g = $b = ($c > $this->image_threshold ? 255 : 0); + $color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']); + imagesetpixel($image_dst, $x, $y, $color); + unset($color); unset($pixel); + } + if (is_numeric($this->image_brightness)) { + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $r = max(min(round($pixel['red'] + (($this->image_brightness * 2))), 255), 0); + $g = max(min(round($pixel['green'] + (($this->image_brightness * 2))), 255), 0); + $b = max(min(round($pixel['blue'] + (($this->image_brightness * 2))), 255), 0); + $color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']); + imagesetpixel($image_dst, $x, $y, $color); + unset($color); unset($pixel); + } + if (is_numeric($this->image_contrast)) { + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $r = max(min(round(($this->image_contrast + 128) * $pixel['red'] / 128), 255), 0); + $g = max(min(round(($this->image_contrast + 128) * $pixel['green'] / 128), 255), 0); + $b = max(min(round(($this->image_contrast + 128) * $pixel['blue'] / 128), 255), 0); + $color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']); + imagesetpixel($image_dst, $x, $y, $color); + unset($color); unset($pixel); + } + if (!empty($this->image_tint_color)) { + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $r = min(round($tint_red * $pixel['red'] / 169), 255); + $g = min(round($tint_green * $pixel['green'] / 169), 255); + $b = min(round($tint_blue * $pixel['blue'] / 169), 255); + $color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']); + imagesetpixel($image_dst, $x, $y, $color); + unset($color); unset($pixel); + } + if (!empty($this->image_negative)) { + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $r = round(255 - $pixel['red']); + $g = round(255 - $pixel['green']); + $b = round(255 - $pixel['blue']); + $color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']); + imagesetpixel($image_dst, $x, $y, $color); + unset($color); unset($pixel); + } + } + } + } + + // adds a border + if ($gd_version >= 2 && !empty($this->image_border)) { + list($ct, $cr, $cb, $cl) = $this->getoffsets($this->image_border, $this->image_dst_x, $this->image_dst_y, true, false); + $this->log .= '- add border : ' . $ct . ' ' . $cr . ' ' . $cb . ' ' . $cl . '
    '; + $this->image_dst_x = $this->image_dst_x + $cl + $cr; + $this->image_dst_y = $this->image_dst_y + $ct + $cb; + if (!empty($this->image_border_color)) list($red, $green, $blue) = $this->getcolors($this->image_border_color); + $opacity = (is_numeric($this->image_border_opacity) ? (int) (127 - $this->image_border_opacity / 100 * 127): 0); + // we now create an image, that we fill with the border color + $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y); + $background = imagecolorallocatealpha($tmp, $red, $green, $blue, $opacity); + imagefilledrectangle($tmp, 0, 0, $this->image_dst_x, $this->image_dst_y, $background); + // we then copy the source image into the new image, without merging so that only the border is actually kept + imagecopy($tmp, $image_dst, $cl, $ct, 0, 0, $this->image_dst_x - $cr - $cl, $this->image_dst_y - $cb - $ct); + // we transfert tmp into image_dst + $image_dst = $this->imagetransfer($tmp, $image_dst); + } + + // adds a fading-to-transparent border + if ($gd_version >= 2 && !empty($this->image_border_transparent)) { + list($ct, $cr, $cb, $cl) = $this->getoffsets($this->image_border_transparent, $this->image_dst_x, $this->image_dst_y, true, false); + $this->log .= '- add transparent border : ' . $ct . ' ' . $cr . ' ' . $cb . ' ' . $cl . '
    '; + // we now create an image, that we fill with the border color + $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y); + // we then copy the source image into the new image, without the borders + imagecopy($tmp, $image_dst, $cl, $ct, $cl, $ct, $this->image_dst_x - $cr - $cl, $this->image_dst_y - $cb - $ct); + // we now add the top border + $opacity = 100; + for ($y = $ct - 1; $y >= 0; $y--) { + $il = (int) ($ct > 0 ? ($cl * ($y / $ct)) : 0); + $ir = (int) ($ct > 0 ? ($cr * ($y / $ct)) : 0); + for ($x = $il; $x < $this->image_dst_x - $ir; $x++) { + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $alpha = (1 - ($pixel['alpha'] / 127)) * $opacity / 100; + if ($alpha > 0) { + if ($alpha > 1) $alpha = 1; + $color = imagecolorallocatealpha($tmp, $pixel['red'] , $pixel['green'], $pixel['blue'], round((1 - $alpha) * 127)); + imagesetpixel($tmp, $x, $y, $color); + } + } + if ($opacity > 0) $opacity = $opacity - (100 / $ct); + } + // we now add the right border + $opacity = 100; + for ($x = $this->image_dst_x - $cr; $x < $this->image_dst_x; $x++) { + $it = (int) ($cr > 0 ? ($ct * (($this->image_dst_x - $x - 1) / $cr)) : 0); + $ib = (int) ($cr > 0 ? ($cb * (($this->image_dst_x - $x - 1) / $cr)) : 0); + for ($y = $it; $y < $this->image_dst_y - $ib; $y++) { + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $alpha = (1 - ($pixel['alpha'] / 127)) * $opacity / 100; + if ($alpha > 0) { + if ($alpha > 1) $alpha = 1; + $color = imagecolorallocatealpha($tmp, $pixel['red'] , $pixel['green'], $pixel['blue'], round((1 - $alpha) * 127)); + imagesetpixel($tmp, $x, $y, $color); + } + } + if ($opacity > 0) $opacity = $opacity - (100 / $cr); + } + // we now add the bottom border + $opacity = 100; + for ($y = $this->image_dst_y - $cb; $y < $this->image_dst_y; $y++) { + $il = (int) ($cb > 0 ? ($cl * (($this->image_dst_y - $y - 1) / $cb)) : 0); + $ir = (int) ($cb > 0 ? ($cr * (($this->image_dst_y - $y - 1) / $cb)) : 0); + for ($x = $il; $x < $this->image_dst_x - $ir; $x++) { + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $alpha = (1 - ($pixel['alpha'] / 127)) * $opacity / 100; + if ($alpha > 0) { + if ($alpha > 1) $alpha = 1; + $color = imagecolorallocatealpha($tmp, $pixel['red'] , $pixel['green'], $pixel['blue'], round((1 - $alpha) * 127)); + imagesetpixel($tmp, $x, $y, $color); + } + } + if ($opacity > 0) $opacity = $opacity - (100 / $cb); + } + // we now add the left border + $opacity = 100; + for ($x = $cl - 1; $x >= 0; $x--) { + $it = (int) ($cl > 0 ? ($ct * ($x / $cl)) : 0); + $ib = (int) ($cl > 0 ? ($cb * ($x / $cl)) : 0); + for ($y = $it; $y < $this->image_dst_y - $ib; $y++) { + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $alpha = (1 - ($pixel['alpha'] / 127)) * $opacity / 100; + if ($alpha > 0) { + if ($alpha > 1) $alpha = 1; + $color = imagecolorallocatealpha($tmp, $pixel['red'] , $pixel['green'], $pixel['blue'], round((1 - $alpha) * 127)); + imagesetpixel($tmp, $x, $y, $color); + } + } + if ($opacity > 0) $opacity = $opacity - (100 / $cl); + } + // we transfert tmp into image_dst + $image_dst = $this->imagetransfer($tmp, $image_dst); + } + + // add frame border + if ($gd_version >= 2 && is_numeric($this->image_frame)) { + if (is_array($this->image_frame_colors)) { + $vars = $this->image_frame_colors; + $this->log .= '- add frame : ' . implode(' ', $this->image_frame_colors) . '
    '; + } else { + $this->log .= '- add frame : ' . $this->image_frame_colors . '
    '; + $vars = explode(' ', $this->image_frame_colors); + } + $nb = sizeof($vars); + $this->image_dst_x = $this->image_dst_x + ($nb * 2); + $this->image_dst_y = $this->image_dst_y + ($nb * 2); + $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y); + imagecopy($tmp, $image_dst, $nb, $nb, 0, 0, $this->image_dst_x - ($nb * 2), $this->image_dst_y - ($nb * 2)); + $opacity = (is_numeric($this->image_frame_opacity) ? (int) (127 - $this->image_frame_opacity / 100 * 127): 0); + for ($i=0; $i<$nb; $i++) { + list($red, $green, $blue) = $this->getcolors($vars[$i]); + $c = imagecolorallocatealpha($tmp, $red, $green, $blue, $opacity); + if ($this->image_frame == 1) { + imageline($tmp, $i, $i, $this->image_dst_x - $i -1, $i, $c); + imageline($tmp, $this->image_dst_x - $i -1, $this->image_dst_y - $i -1, $this->image_dst_x - $i -1, $i, $c); + imageline($tmp, $this->image_dst_x - $i -1, $this->image_dst_y - $i -1, $i, $this->image_dst_y - $i -1, $c); + imageline($tmp, $i, $i, $i, $this->image_dst_y - $i -1, $c); + } else { + imageline($tmp, $i, $i, $this->image_dst_x - $i -1, $i, $c); + imageline($tmp, $this->image_dst_x - $nb + $i, $this->image_dst_y - $nb + $i, $this->image_dst_x - $nb + $i, $nb - $i, $c); + imageline($tmp, $this->image_dst_x - $nb + $i, $this->image_dst_y - $nb + $i, $nb - $i, $this->image_dst_y - $nb + $i, $c); + imageline($tmp, $i, $i, $i, $this->image_dst_y - $i -1, $c); + } + } + // we transfert tmp into image_dst + $image_dst = $this->imagetransfer($tmp, $image_dst); + } + + // add bevel border + if ($gd_version >= 2 && $this->image_bevel > 0) { + if (empty($this->image_bevel_color1)) $this->image_bevel_color1 = '#FFFFFF'; + if (empty($this->image_bevel_color2)) $this->image_bevel_color2 = '#000000'; + list($red1, $green1, $blue1) = $this->getcolors($this->image_bevel_color1); + list($red2, $green2, $blue2) = $this->getcolors($this->image_bevel_color2); + $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y); + imagecopy($tmp, $image_dst, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y); + imagealphablending($tmp, true); + for ($i=0; $i<$this->image_bevel; $i++) { + $alpha = round(($i / $this->image_bevel) * 127); + $c1 = imagecolorallocatealpha($tmp, $red1, $green1, $blue1, $alpha); + $c2 = imagecolorallocatealpha($tmp, $red2, $green2, $blue2, $alpha); + imageline($tmp, $i, $i, $this->image_dst_x - $i -1, $i, $c1); + imageline($tmp, $this->image_dst_x - $i -1, $this->image_dst_y - $i, $this->image_dst_x - $i -1, $i, $c2); + imageline($tmp, $this->image_dst_x - $i -1, $this->image_dst_y - $i -1, $i, $this->image_dst_y - $i -1, $c2); + imageline($tmp, $i, $i, $i, $this->image_dst_y - $i -1, $c1); + } + // we transfert tmp into image_dst + $image_dst = $this->imagetransfer($tmp, $image_dst); + } + + // add watermark image + if ($this->image_watermark!='' && file_exists($this->image_watermark)) { + $this->log .= '- add watermark
    '; + $this->image_watermark_position = strtolower($this->image_watermark_position); + $watermark_info = getimagesize($this->image_watermark); + $watermark_type = (array_key_exists(2, $watermark_info) ? $watermark_info[2] : null); // 1 = GIF, 2 = JPG, 3 = PNG + $watermark_checked = false; + if ($watermark_type == IMAGETYPE_GIF) { + if (!function_exists('imagecreatefromgif')) { + $this->error = $this->translate('watermark_no_create_support', array('GIF')); + } else { + $filter = @imagecreatefromgif($this->image_watermark); + if (!$filter) { + $this->error = $this->translate('watermark_create_error', array('GIF')); + } else { + $this->log .= '    watermark source image is GIF
    '; + $watermark_checked = true; + } + } + } else if ($watermark_type == IMAGETYPE_JPEG) { + if (!function_exists('imagecreatefromjpeg')) { + $this->error = $this->translate('watermark_no_create_support', array('JPEG')); + } else { + $filter = @imagecreatefromjpeg($this->image_watermark); + if (!$filter) { + $this->error = $this->translate('watermark_create_error', array('JPEG')); + } else { + $this->log .= '    watermark source image is JPEG
    '; + $watermark_checked = true; + } + } + } else if ($watermark_type == IMAGETYPE_PNG) { + if (!function_exists('imagecreatefrompng')) { + $this->error = $this->translate('watermark_no_create_support', array('PNG')); + } else { + $filter = @imagecreatefrompng($this->image_watermark); + if (!$filter) { + $this->error = $this->translate('watermark_create_error', array('PNG')); + } else { + $this->log .= '    watermark source image is PNG
    '; + $watermark_checked = true; + } + } + } else if ($watermark_type == IMAGETYPE_BMP) { + if (!method_exists($this, 'imagecreatefrombmp')) { + $this->error = $this->translate('watermark_no_create_support', array('BMP')); + } else { + $filter = @$this->imagecreatefrombmp($this->image_watermark); + if (!$filter) { + $this->error = $this->translate('watermark_create_error', array('BMP')); + } else { + $this->log .= '    watermark source image is BMP
    '; + $watermark_checked = true; + } + } + } else { + $this->error = $this->translate('watermark_invalid'); + } + if ($watermark_checked) { + $watermark_dst_width = $watermark_src_width = imagesx($filter); + $watermark_dst_height = $watermark_src_height = imagesy($filter); + + // if watermark is too large/tall, resize it first + if ((!$this->image_watermark_no_zoom_out && ($watermark_dst_width > $this->image_dst_x || $watermark_dst_height > $this->image_dst_y)) + || (!$this->image_watermark_no_zoom_in && $watermark_dst_width < $this->image_dst_x && $watermark_dst_height < $this->image_dst_y)) { + $canvas_width = $this->image_dst_x - abs($this->image_watermark_x); + $canvas_height = $this->image_dst_y - abs($this->image_watermark_y); + if (($watermark_src_width/$canvas_width) > ($watermark_src_height/$canvas_height)) { + $watermark_dst_width = $canvas_width; + $watermark_dst_height = intval($watermark_src_height*($canvas_width / $watermark_src_width)); + } else { + $watermark_dst_height = $canvas_height; + $watermark_dst_width = intval($watermark_src_width*($canvas_height / $watermark_src_height)); + } + $this->log .= '    watermark resized from '.$watermark_src_width.'x'.$watermark_src_height.' to '.$watermark_dst_width.'x'.$watermark_dst_height.'
    '; + + } + // determine watermark position + $watermark_x = 0; + $watermark_y = 0; + if (is_numeric($this->image_watermark_x)) { + if ($this->image_watermark_x < 0) { + $watermark_x = $this->image_dst_x - $watermark_dst_width + $this->image_watermark_x; + } else { + $watermark_x = $this->image_watermark_x; + } + } else { + if (strpos($this->image_watermark_position, 'r') !== false) { + $watermark_x = $this->image_dst_x - $watermark_dst_width; + } else if (strpos($this->image_watermark_position, 'l') !== false) { + $watermark_x = 0; + } else { + $watermark_x = ($this->image_dst_x - $watermark_dst_width) / 2; + } + } + if (is_numeric($this->image_watermark_y)) { + if ($this->image_watermark_y < 0) { + $watermark_y = $this->image_dst_y - $watermark_dst_height + $this->image_watermark_y; + } else { + $watermark_y = $this->image_watermark_y; + } + } else { + if (strpos($this->image_watermark_position, 'b') !== false) { + $watermark_y = $this->image_dst_y - $watermark_dst_height; + } else if (strpos($this->image_watermark_position, 't') !== false) { + $watermark_y = 0; + } else { + $watermark_y = ($this->image_dst_y - $watermark_dst_height) / 2; + } + } + imagealphablending($image_dst, true); + imagecopyresampled($image_dst, $filter, $watermark_x, $watermark_y, 0, 0, $watermark_dst_width, $watermark_dst_height, $watermark_src_width, $watermark_src_height); + } else { + $this->error = $this->translate('watermark_invalid'); + } + } + + // add text + if (!empty($this->image_text)) { + $this->log .= '- add text
    '; + + // calculate sizes in human readable format + $src_size = $this->file_src_size / 1024; + $src_size_mb = number_format($src_size / 1024, 1, ".", " "); + $src_size_kb = number_format($src_size, 1, ".", " "); + $src_size_human = ($src_size > 1024 ? $src_size_mb . " MB" : $src_size_kb . " kb"); + + $this->image_text = str_replace( + array('[src_name]', + '[src_name_body]', + '[src_name_ext]', + '[src_pathname]', + '[src_mime]', + '[src_size]', + '[src_size_kb]', + '[src_size_mb]', + '[src_size_human]', + '[src_x]', + '[src_y]', + '[src_pixels]', + '[src_type]', + '[src_bits]', + '[dst_path]', + '[dst_name_body]', + '[dst_name_ext]', + '[dst_name]', + '[dst_pathname]', + '[dst_x]', + '[dst_y]', + '[date]', + '[time]', + '[host]', + '[server]', + '[ip]', + '[gd_version]'), + array($this->file_src_name, + $this->file_src_name_body, + $this->file_src_name_ext, + $this->file_src_pathname, + $this->file_src_mime, + $this->file_src_size, + $src_size_kb, + $src_size_mb, + $src_size_human, + $this->image_src_x, + $this->image_src_y, + $this->image_src_pixels, + $this->image_src_type, + $this->image_src_bits, + $this->file_dst_path, + $this->file_dst_name_body, + $this->file_dst_name_ext, + $this->file_dst_name, + $this->file_dst_pathname, + $this->image_dst_x, + $this->image_dst_y, + date('Y-m-d'), + date('H:i:s'), + (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'n/a'), + (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'n/a'), + (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'n/a'), + $this->gdversion(true)), + $this->image_text); + + if (!is_numeric($this->image_text_padding)) $this->image_text_padding = 0; + if (!is_numeric($this->image_text_line_spacing)) $this->image_text_line_spacing = 0; + if (!is_numeric($this->image_text_padding_x)) $this->image_text_padding_x = $this->image_text_padding; + if (!is_numeric($this->image_text_padding_y)) $this->image_text_padding_y = $this->image_text_padding; + $this->image_text_position = strtolower($this->image_text_position); + $this->image_text_direction = strtolower($this->image_text_direction); + $this->image_text_alignment = strtolower($this->image_text_alignment); + + // if the font is a string, we assume that we might want to load a font + if (!is_numeric($this->image_text_font) && strlen($this->image_text_font) > 4 && substr(strtolower($this->image_text_font), -4) == '.gdf') { + $this->log .= '    try to load font ' . $this->image_text_font . '... '; + if ($this->image_text_font = @imageloadfont($this->image_text_font)) { + $this->log .= 'success
    '; + } else { + $this->log .= 'error
    '; + $this->image_text_font = 5; + } + } + + $text = explode("\n", $this->image_text); + $char_width = imagefontwidth($this->image_text_font); + $char_height = imagefontheight($this->image_text_font); + $text_height = 0; + $text_width = 0; + $line_height = 0; + $line_width = 0; + + foreach ($text as $k => $v) { + if ($this->image_text_direction == 'v') { + $h = ($char_width * strlen($v)); + if ($h > $text_height) $text_height = $h; + $line_width = $char_height; + $text_width += $line_width + ($k < (sizeof($text)-1) ? $this->image_text_line_spacing : 0); + } else { + $w = ($char_width * strlen($v)); + if ($w > $text_width) $text_width = $w; + $line_height = $char_height; + $text_height += $line_height + ($k < (sizeof($text)-1) ? $this->image_text_line_spacing : 0); + } + } + $text_width += (2 * $this->image_text_padding_x); + $text_height += (2 * $this->image_text_padding_y); + $text_x = 0; + $text_y = 0; + if (is_numeric($this->image_text_x)) { + if ($this->image_text_x < 0) { + $text_x = $this->image_dst_x - $text_width + $this->image_text_x; + } else { + $text_x = $this->image_text_x; + } + } else { + if (strpos($this->image_text_position, 'r') !== false) { + $text_x = $this->image_dst_x - $text_width; + } else if (strpos($this->image_text_position, 'l') !== false) { + $text_x = 0; + } else { + $text_x = ($this->image_dst_x - $text_width) / 2; + } + } + if (is_numeric($this->image_text_y)) { + if ($this->image_text_y < 0) { + $text_y = $this->image_dst_y - $text_height + $this->image_text_y; + } else { + $text_y = $this->image_text_y; + } + } else { + if (strpos($this->image_text_position, 'b') !== false) { + $text_y = $this->image_dst_y - $text_height; + } else if (strpos($this->image_text_position, 't') !== false) { + $text_y = 0; + } else { + $text_y = ($this->image_dst_y - $text_height) / 2; + } + } + + // add a background, maybe transparent + if (!empty($this->image_text_background)) { + list($red, $green, $blue) = $this->getcolors($this->image_text_background); + if ($gd_version >= 2 && (is_numeric($this->image_text_background_opacity)) && $this->image_text_background_opacity >= 0 && $this->image_text_background_opacity <= 100) { + $filter = imagecreatetruecolor($text_width, $text_height); + $background_color = imagecolorallocate($filter, $red, $green, $blue); + imagefilledrectangle($filter, 0, 0, $text_width, $text_height, $background_color); + $this->imagecopymergealpha($image_dst, $filter, $text_x, $text_y, 0, 0, $text_width, $text_height, $this->image_text_background_opacity); + imagedestroy($filter); + } else { + $background_color = imagecolorallocate($image_dst ,$red, $green, $blue); + imagefilledrectangle($image_dst, $text_x, $text_y, $text_x + $text_width, $text_y + $text_height, $background_color); + } + } + + $text_x += $this->image_text_padding_x; + $text_y += $this->image_text_padding_y; + $t_width = $text_width - (2 * $this->image_text_padding_x); + $t_height = $text_height - (2 * $this->image_text_padding_y); + list($red, $green, $blue) = $this->getcolors($this->image_text_color); + + // add the text, maybe transparent + if ($gd_version >= 2 && (is_numeric($this->image_text_opacity)) && $this->image_text_opacity >= 0 && $this->image_text_opacity <= 100) { + if ($t_width < 0) $t_width = 0; + if ($t_height < 0) $t_height = 0; + $filter = $this->imagecreatenew($t_width, $t_height, false, true); + $text_color = imagecolorallocate($filter ,$red, $green, $blue); + + foreach ($text as $k => $v) { + if ($this->image_text_direction == 'v') { + imagestringup($filter, + $this->image_text_font, + $k * ($line_width + ($k > 0 && $k < (sizeof($text)) ? $this->image_text_line_spacing : 0)), + $text_height - (2 * $this->image_text_padding_y) - ($this->image_text_alignment == 'l' ? 0 : (($t_height - strlen($v) * $char_width) / ($this->image_text_alignment == 'r' ? 1 : 2))) , + $v, + $text_color); + } else { + imagestring($filter, + $this->image_text_font, + ($this->image_text_alignment == 'l' ? 0 : (($t_width - strlen($v) * $char_width) / ($this->image_text_alignment == 'r' ? 1 : 2))), + $k * ($line_height + ($k > 0 && $k < (sizeof($text)) ? $this->image_text_line_spacing : 0)), + $v, + $text_color); + } + } + $this->imagecopymergealpha($image_dst, $filter, $text_x, $text_y, 0, 0, $t_width, $t_height, $this->image_text_opacity); + imagedestroy($filter); + + } else { + $text_color = imageColorAllocate($image_dst ,$red, $green, $blue); + foreach ($text as $k => $v) { + if ($this->image_text_direction == 'v') { + imagestringup($image_dst, + $this->image_text_font, + $text_x + $k * ($line_width + ($k > 0 && $k < (sizeof($text)) ? $this->image_text_line_spacing : 0)), + $text_y + $text_height - (2 * $this->image_text_padding_y) - ($this->image_text_alignment == 'l' ? 0 : (($t_height - strlen($v) * $char_width) / ($this->image_text_alignment == 'r' ? 1 : 2))), + $v, + $text_color); + } else { + imagestring($image_dst, + $this->image_text_font, + $text_x + ($this->image_text_alignment == 'l' ? 0 : (($t_width - strlen($v) * $char_width) / ($this->image_text_alignment == 'r' ? 1 : 2))), + $text_y + $k * ($line_height + ($k > 0 && $k < (sizeof($text)) ? $this->image_text_line_spacing : 0)), + $v, + $text_color); + } + } + } + } + + // add a reflection + if ($this->image_reflection_height) { + $this->log .= '- add reflection : ' . $this->image_reflection_height . '
    '; + // we decode image_reflection_height, which can be a integer, a string in pixels or percentage + $image_reflection_height = $this->image_reflection_height; + if (strpos($image_reflection_height, '%')>0) $image_reflection_height = $this->image_dst_y * (str_replace('%','',$image_reflection_height / 100)); + if (strpos($image_reflection_height, 'px')>0) $image_reflection_height = str_replace('px','',$image_reflection_height); + $image_reflection_height = (int) $image_reflection_height; + if ($image_reflection_height > $this->image_dst_y) $image_reflection_height = $this->image_dst_y; + if (empty($this->image_reflection_opacity)) $this->image_reflection_opacity = 60; + // create the new destination image + $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y + $image_reflection_height + $this->image_reflection_space, true); + $transparency = $this->image_reflection_opacity; + + // copy the original image + imagecopy($tmp, $image_dst, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y + ($this->image_reflection_space < 0 ? $this->image_reflection_space : 0)); + + // we have to make sure the extra bit is the right color, or transparent + if ($image_reflection_height + $this->image_reflection_space > 0) { + // use the background color if present + if (!empty($this->image_background_color)) { + list($red, $green, $blue) = $this->getcolors($this->image_background_color); + $fill = imagecolorallocate($tmp, $red, $green, $blue); + } else { + $fill = imagecolorallocatealpha($tmp, 0, 0, 0, 127); + } + // fill in from the edge of the extra bit + imagefill($tmp, round($this->image_dst_x / 2), $this->image_dst_y + $image_reflection_height + $this->image_reflection_space - 1, $fill); + } + + // copy the reflection + for ($y = 0; $y < $image_reflection_height; $y++) { + for ($x = 0; $x < $this->image_dst_x; $x++) { + $pixel_b = imagecolorsforindex($tmp, imagecolorat($tmp, $x, $y + $this->image_dst_y + $this->image_reflection_space)); + $pixel_o = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $this->image_dst_y - $y - 1 + ($this->image_reflection_space < 0 ? $this->image_reflection_space : 0))); + $alpha_o = 1 - ($pixel_o['alpha'] / 127); + $alpha_b = 1 - ($pixel_b['alpha'] / 127); + $opacity = $alpha_o * $transparency / 100; + if ($opacity > 0) { + $red = round((($pixel_o['red'] * $opacity) + ($pixel_b['red'] ) * $alpha_b) / ($alpha_b + $opacity)); + $green = round((($pixel_o['green'] * $opacity) + ($pixel_b['green']) * $alpha_b) / ($alpha_b + $opacity)); + $blue = round((($pixel_o['blue'] * $opacity) + ($pixel_b['blue'] ) * $alpha_b) / ($alpha_b + $opacity)); + $alpha = ($opacity + $alpha_b); + if ($alpha > 1) $alpha = 1; + $alpha = round((1 - $alpha) * 127); + $color = imagecolorallocatealpha($tmp, $red, $green, $blue, $alpha); + imagesetpixel($tmp, $x, $y + $this->image_dst_y + $this->image_reflection_space, $color); + } + } + if ($transparency > 0) $transparency = $transparency - ($this->image_reflection_opacity / $image_reflection_height); + } + + // copy the resulting image into the destination image + $this->image_dst_y = $this->image_dst_y + $image_reflection_height + $this->image_reflection_space; + $image_dst = $this->imagetransfer($tmp, $image_dst); + } + + // change opacity + if ($gd_version >= 2 && is_numeric($this->image_opacity) && $this->image_opacity < 100) { + $this->log .= '- change opacity
    '; + // create the new destination image + $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y, true); + for($y=0; $y < $this->image_dst_y; $y++) { + for($x=0; $x < $this->image_dst_x; $x++) { + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $alpha = $pixel['alpha'] + round((127 - $pixel['alpha']) * (100 - $this->image_opacity) / 100); + if ($alpha > 127) $alpha = 127; + if ($alpha > 0) { + $color = imagecolorallocatealpha($tmp, $pixel['red'] , $pixel['green'], $pixel['blue'], $alpha); + imagesetpixel($tmp, $x, $y, $color); + } + } + } + // copy the resulting image into the destination image + $image_dst = $this->imagetransfer($tmp, $image_dst); + } + + // reduce the JPEG image to a set desired size + if (is_numeric($this->jpeg_size) && $this->jpeg_size > 0 && ($this->image_convert == 'jpeg' || $this->image_convert == 'jpg')) { + // inspired by: JPEGReducer class version 1, 25 November 2004, Author: Huda M ElMatsani, justhuda at netscape dot net + $this->log .= '- JPEG desired file size : ' . $this->jpeg_size . '
    '; + // calculate size of each image. 75%, 50%, and 25% quality + ob_start(); imagejpeg($image_dst,null,75); $buffer = ob_get_contents(); ob_end_clean(); + $size75 = strlen($buffer); + ob_start(); imagejpeg($image_dst,null,50); $buffer = ob_get_contents(); ob_end_clean(); + $size50 = strlen($buffer); + ob_start(); imagejpeg($image_dst,null,25); $buffer = ob_get_contents(); ob_end_clean(); + $size25 = strlen($buffer); + + // make sure we won't divide by 0 + if ($size50 == $size25) $size50++; + if ($size75 == $size50 || $size75 == $size25) $size75++; + + // calculate gradient of size reduction by quality + $mgrad1 = 25 / ($size50-$size25); + $mgrad2 = 25 / ($size75-$size50); + $mgrad3 = 50 / ($size75-$size25); + $mgrad = ($mgrad1 + $mgrad2 + $mgrad3) / 3; + // result of approx. quality factor for expected size + $q_factor = round($mgrad * ($this->jpeg_size - $size50) + 50); + + if ($q_factor<1) { + $this->jpeg_quality=1; + } elseif ($q_factor>100) { + $this->jpeg_quality=100; + } else { + $this->jpeg_quality=$q_factor; + } + $this->log .= '    JPEG quality factor set to ' . $this->jpeg_quality . '
    '; + } + + // converts image from true color, and fix transparency if needed + $this->log .= '- converting...
    '; + switch($this->image_convert) { + case 'gif': + // if the image is true color, we convert it to a palette + if (imageistruecolor($image_dst)) { + $this->log .= '    true color to palette
    '; + // creates a black and white mask + $mask = array(array()); + for ($x = 0; $x < $this->image_dst_x; $x++) { + for ($y = 0; $y < $this->image_dst_y; $y++) { + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $mask[$x][$y] = $pixel['alpha']; + } + } + list($red, $green, $blue) = $this->getcolors($this->image_default_color); + // first, we merge the image with the background color, so we know which colors we will have + for ($x = 0; $x < $this->image_dst_x; $x++) { + for ($y = 0; $y < $this->image_dst_y; $y++) { + if ($mask[$x][$y] > 0){ + // we have some transparency. we combine the color with the default color + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + $alpha = ($mask[$x][$y] / 127); + $pixel['red'] = round(($pixel['red'] * (1 -$alpha) + $red * ($alpha))); + $pixel['green'] = round(($pixel['green'] * (1 -$alpha) + $green * ($alpha))); + $pixel['blue'] = round(($pixel['blue'] * (1 -$alpha) + $blue * ($alpha))); + $color = imagecolorallocate($image_dst, $pixel['red'], $pixel['green'], $pixel['blue']); + imagesetpixel($image_dst, $x, $y, $color); + } + } + } + // transforms the true color image into palette, with its merged default color + if (empty($this->image_background_color)) { + imagetruecolortopalette($image_dst, true, 255); + $transparency = imagecolorallocate($image_dst, 254, 1, 253); + imagecolortransparent($image_dst, $transparency); + // make the transparent areas transparent + for ($x = 0; $x < $this->image_dst_x; $x++) { + for ($y = 0; $y < $this->image_dst_y; $y++) { + // we test wether we have enough opacity to justify keeping the color + if ($mask[$x][$y] > 120) imagesetpixel($image_dst, $x, $y, $transparency); + } + } + } + unset($mask); + } + break; + case 'jpg': + case 'bmp': + // if the image doesn't support any transparency, then we merge it with the default color + $this->log .= '    fills in transparency with default color
    '; + list($red, $green, $blue) = $this->getcolors($this->image_default_color); + $transparency = imagecolorallocate($image_dst, $red, $green, $blue); + // make the transaparent areas transparent + for ($x = 0; $x < $this->image_dst_x; $x++) { + for ($y = 0; $y < $this->image_dst_y; $y++) { + // we test wether we have some transparency, in which case we will merge the colors + if (imageistruecolor($image_dst)) { + $rgba = imagecolorat($image_dst, $x, $y); + $pixel = array('red' => ($rgba >> 16) & 0xFF, + 'green' => ($rgba >> 8) & 0xFF, + 'blue' => $rgba & 0xFF, + 'alpha' => ($rgba & 0x7F000000) >> 24); + } else { + $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y)); + } + if ($pixel['alpha'] == 127) { + // we have full transparency. we make the pixel transparent + imagesetpixel($image_dst, $x, $y, $transparency); + } else if ($pixel['alpha'] > 0) { + // we have some transparency. we combine the color with the default color + $alpha = ($pixel['alpha'] / 127); + $pixel['red'] = round(($pixel['red'] * (1 -$alpha) + $red * ($alpha))); + $pixel['green'] = round(($pixel['green'] * (1 -$alpha) + $green * ($alpha))); + $pixel['blue'] = round(($pixel['blue'] * (1 -$alpha) + $blue * ($alpha))); + $color = imagecolorclosest($image_dst, $pixel['red'], $pixel['green'], $pixel['blue']); + imagesetpixel($image_dst, $x, $y, $color); + } + } + } + + break; + default: + break; + } + + // interlace options + if($this->image_interlace) imageinterlace($image_dst, true); + + // outputs image + $this->log .= '- saving image...
    '; + switch($this->image_convert) { + case 'jpeg': + case 'jpg': + if (!$return_mode) { + $result = @imagejpeg($image_dst, $this->file_dst_pathname, $this->jpeg_quality); + } else { + ob_start(); + $result = @imagejpeg($image_dst, null, $this->jpeg_quality); + $return_content = ob_get_contents(); + ob_end_clean(); + } + if (!$result) { + $this->processed = false; + $this->error = $this->translate('file_create', array('JPEG')); + } else { + $this->log .= '    JPEG image created
    '; + } + break; + case 'png': + imagealphablending( $image_dst, false ); + imagesavealpha( $image_dst, true ); + if (!$return_mode) { + if (is_numeric($this->png_compression) && version_compare(PHP_VERSION, '5.1.2') >= 0) { + $result = @imagepng($image_dst, $this->file_dst_pathname, $this->png_compression); + } else { + $result = @imagepng($image_dst, $this->file_dst_pathname); + } + } else { + ob_start(); + if (is_numeric($this->png_compression) && version_compare(PHP_VERSION, '5.1.2') >= 0) { + $result = @imagepng($image_dst, null, $this->png_compression); + } else { + $result = @imagepng($image_dst); + } + $return_content = ob_get_contents(); + ob_end_clean(); + } + if (!$result) { + $this->processed = false; + $this->error = $this->translate('file_create', array('PNG')); + } else { + $this->log .= '    PNG image created
    '; + } + break; + case 'gif': + if (!$return_mode) { + $result = @imagegif($image_dst, $this->file_dst_pathname); + } else { + ob_start(); + $result = @imagegif($image_dst); + $return_content = ob_get_contents(); + ob_end_clean(); + } + if (!$result) { + $this->processed = false; + $this->error = $this->translate('file_create', array('GIF')); + } else { + $this->log .= '    GIF image created
    '; + } + break; + case 'bmp': + if (!$return_mode) { + $result = $this->imagebmp($image_dst, $this->file_dst_pathname); + } else { + ob_start(); + $result = $this->imagebmp($image_dst); + $return_content = ob_get_contents(); + ob_end_clean(); + } + if (!$result) { + $this->processed = false; + $this->error = $this->translate('file_create', array('BMP')); + } else { + $this->log .= '    BMP image created
    '; + } + break; + + default: + $this->processed = false; + $this->error = $this->translate('no_conversion_type'); + } + if ($this->processed) { + if (is_resource($image_src)) imagedestroy($image_src); + if (is_resource($image_dst)) imagedestroy($image_dst); + $this->log .= '    image objects destroyed
    '; + } + } + + } else { + $this->log .= '- no image processing wanted
    '; + + if (!$return_mode) { + // copy the file to its final destination. we don't use move_uploaded_file here + // if we happen to have open_basedir restrictions, it is a temp file that we copy, not the original uploaded file + if (!copy($this->file_src_pathname, $this->file_dst_pathname)) { + $this->processed = false; + $this->error = $this->translate('copy_failed'); + } + } else { + // returns the file, so that its content can be received by the caller + $return_content = @file_get_contents($this->file_src_pathname); + if ($return_content === FALSE) { + $this->processed = false; + $this->error = $this->translate('reading_failed'); + } + } + } + } + + if ($this->processed) { + $this->log .= '- process OK
    '; + } else { + $this->log .= '- error: ' . $this->error . '
    '; + } + + // we reinit all the vars + $this->init(); + + // we may return the image content + if ($return_mode) return $return_content; + + } + + /** + * Deletes the uploaded file from its temporary location + * + * When PHP uploads a file, it stores it in a temporary location. + * When you {@link process} the file, you actually copy the resulting file to the given location, it doesn't alter the original file. + * Once you have processed the file as many times as you wanted, you can delete the uploaded file. + * If there is open_basedir restrictions, the uploaded file is in fact a temporary file + * + * You might want not to use this function if you work on local files, as it will delete the source file + * + * @access public + */ + function clean() { + $this->log .= 'cleanup
    '; + $this->log .= '- delete temp file ' . $this->file_src_pathname . '
    '; + @unlink($this->file_src_pathname); + } + + + /** + * Opens a BMP image + * + * This function has been written by DHKold, and is used with permission of the author + * + * @access public + */ + function imagecreatefrombmp($filename) { + if (! $f1 = fopen($filename,"rb")) return false; + + $file = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1,14)); + if ($file['file_type'] != 19778) return false; + + $bmp = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel'. + '/Vcompression/Vsize_bitmap/Vhoriz_resolution'. + '/Vvert_resolution/Vcolors_used/Vcolors_important', fread($f1,40)); + $bmp['colors'] = pow(2,$bmp['bits_per_pixel']); + if ($bmp['size_bitmap'] == 0) $bmp['size_bitmap'] = $file['file_size'] - $file['bitmap_offset']; + $bmp['bytes_per_pixel'] = $bmp['bits_per_pixel']/8; + $bmp['bytes_per_pixel2'] = ceil($bmp['bytes_per_pixel']); + $bmp['decal'] = ($bmp['width']*$bmp['bytes_per_pixel']/4); + $bmp['decal'] -= floor($bmp['width']*$bmp['bytes_per_pixel']/4); + $bmp['decal'] = 4-(4*$bmp['decal']); + if ($bmp['decal'] == 4) $bmp['decal'] = 0; + + $palette = array(); + if ($bmp['colors'] < 16777216) { + $palette = unpack('V'.$bmp['colors'], fread($f1,$bmp['colors']*4)); + } + + $im = fread($f1,$bmp['size_bitmap']); + $vide = chr(0); + + $res = imagecreatetruecolor($bmp['width'],$bmp['height']); + $P = 0; + $Y = $bmp['height']-1; + while ($Y >= 0) { + $X=0; + while ($X < $bmp['width']) { + if ($bmp['bits_per_pixel'] == 24) + $color = unpack("V",substr($im,$P,3).$vide); + elseif ($bmp['bits_per_pixel'] == 16) { + $color = unpack("n",substr($im,$P,2)); + $color[1] = $palette[$color[1]+1]; + } elseif ($bmp['bits_per_pixel'] == 8) { + $color = unpack("n",$vide.substr($im,$P,1)); + $color[1] = $palette[$color[1]+1]; + } elseif ($bmp['bits_per_pixel'] == 4) { + $color = unpack("n",$vide.substr($im,floor($P),1)); + if (($P*2)%2 == 0) $color[1] = ($color[1] >> 4) ; else $color[1] = ($color[1] & 0x0F); + $color[1] = $palette[$color[1]+1]; + } elseif ($bmp['bits_per_pixel'] == 1) { + $color = unpack("n",$vide.substr($im,floor($P),1)); + if (($P*8)%8 == 0) $color[1] = $color[1] >>7; + elseif (($P*8)%8 == 1) $color[1] = ($color[1] & 0x40)>>6; + elseif (($P*8)%8 == 2) $color[1] = ($color[1] & 0x20)>>5; + elseif (($P*8)%8 == 3) $color[1] = ($color[1] & 0x10)>>4; + elseif (($P*8)%8 == 4) $color[1] = ($color[1] & 0x8)>>3; + elseif (($P*8)%8 == 5) $color[1] = ($color[1] & 0x4)>>2; + elseif (($P*8)%8 == 6) $color[1] = ($color[1] & 0x2)>>1; + elseif (($P*8)%8 == 7) $color[1] = ($color[1] & 0x1); + $color[1] = $palette[$color[1]+1]; + } else + return FALSE; + imagesetpixel($res,$X,$Y,$color[1]); + $X++; + $P += $bmp['bytes_per_pixel']; + } + $Y--; + $P+=$bmp['decal']; + } + fclose($f1); + return $res; + } + + /** + * Saves a BMP image + * + * This function has been published on the PHP website, and can be used freely + * + * @access public + */ + function imagebmp(&$im, $filename = "") { + + if (!$im) return false; + $w = imagesx($im); + $h = imagesy($im); + $result = ''; + + // if the image is not true color, we convert it first + if (!imageistruecolor($im)) { + $tmp = imagecreatetruecolor($w, $h); + imagecopy($tmp, $im, 0, 0, 0, 0, $w, $h); + imagedestroy($im); + $im = & $tmp; + } + + $biBPLine = $w * 3; + $biStride = ($biBPLine + 3) & ~3; + $biSizeImage = $biStride * $h; + $bfOffBits = 54; + $bfSize = $bfOffBits + $biSizeImage; + + $result .= substr('BM', 0, 2); + $result .= pack ('VvvV', $bfSize, 0, 0, $bfOffBits); + $result .= pack ('VVVvvVVVVVV', 40, $w, $h, 1, 24, 0, $biSizeImage, 0, 0, 0, 0); + + $numpad = $biStride - $biBPLine; + for ($y = $h - 1; $y >= 0; --$y) { + for ($x = 0; $x < $w; ++$x) { + $col = imagecolorat ($im, $x, $y); + $result .= substr(pack ('V', $col), 0, 3); + } + for ($i = 0; $i < $numpad; ++$i) + $result .= pack ('C', 0); + } + + if($filename==""){ + echo $result; + } else { + $file = fopen($filename, "wb"); + fwrite($file, $result); + fclose($file); + } + return true; + } +} \ No newline at end of file diff --git a/administrator/components/com_k2/lib/elfinder/elFinder.class.php b/administrator/components/com_k2/lib/elfinder/elFinder.class.php new file mode 100644 index 0000000..89d46a5 --- /dev/null +++ b/administrator/components/com_k2/lib/elfinder/elFinder.class.php @@ -0,0 +1,1113 @@ + array('target' => false, 'tree' => false, 'init' => false, 'mimes' => false), + 'ls' => array('target' => true, 'mimes' => false), + 'tree' => array('target' => true), + 'parents' => array('target' => true), + 'tmb' => array('targets' => true), + 'file' => array('target' => true, 'download' => false), + 'size' => array('targets' => true), + 'mkdir' => array('target' => true, 'name' => true), + 'mkfile' => array('target' => true, 'name' => true, 'mimes' => false), + 'rm' => array('targets' => true), + 'rename' => array('target' => true, 'name' => true, 'mimes' => false), + 'duplicate' => array('targets' => true, 'suffix' => false), + 'paste' => array('dst' => true, 'targets' => true, 'cut' => false, 'mimes' => false), + 'upload' => array('target' => true, 'FILES' => true, 'mimes' => false, 'html' => false), + 'get' => array('target' => true), + 'put' => array('target' => true, 'content' => '', 'mimes' => false), + 'archive' => array('targets' => true, 'type' => true, 'mimes' => false), + 'extract' => array('target' => true, 'mimes' => false), + 'search' => array('q' => true, 'mimes' => false), + 'info' => array('targets' => true), + 'dim' => array('target' => true), + 'resize' => array('target' => true, 'width' => true, 'height' => true, 'mode' => false, 'x' => false, 'y' => false, 'degree' => false) + ); + + /** + * Commands listeners + * + * @var array + **/ + protected $listeners = array(); + + /** + * script work time for debug + * + * @var string + **/ + protected $time = 0; + /** + * Is elFinder init correctly? + * + * @var bool + **/ + protected $loaded = false; + /** + * Send debug to client? + * + * @var string + **/ + protected $debug = false; + + /** + * undocumented class variable + * + * @var string + **/ + protected $uploadDebug = ''; + + /** + * Errors from not mounted volumes + * + * @var array + **/ + public $mountErrors = array(); + + // Errors messages + const ERROR_UNKNOWN = 'errUnknown'; + const ERROR_UNKNOWN_CMD = 'errUnknownCmd'; + const ERROR_CONF = 'errConf'; + const ERROR_CONF_NO_JSON = 'errJSON'; + const ERROR_CONF_NO_VOL = 'errNoVolumes'; + const ERROR_INV_PARAMS = 'errCmdParams'; + const ERROR_OPEN = 'errOpen'; + const ERROR_DIR_NOT_FOUND = 'errFolderNotFound'; + const ERROR_FILE_NOT_FOUND = 'errFileNotFound'; // 'File not found.' + const ERROR_TRGDIR_NOT_FOUND = 'errTrgFolderNotFound'; // 'Target folder "$1" not found.' + const ERROR_NOT_DIR = 'errNotFolder'; + const ERROR_NOT_FILE = 'errNotFile'; + const ERROR_PERM_DENIED = 'errPerm'; + const ERROR_LOCKED = 'errLocked'; // '"$1" is locked and can not be renamed, moved or removed.' + const ERROR_EXISTS = 'errExists'; // 'File named "$1" already exists.' + const ERROR_INVALID_NAME = 'errInvName'; // 'Invalid file name.' + const ERROR_MKDIR = 'errMkdir'; + const ERROR_MKFILE = 'errMkfile'; + const ERROR_RENAME = 'errRename'; + const ERROR_COPY = 'errCopy'; + const ERROR_MOVE = 'errMove'; + const ERROR_COPY_FROM = 'errCopyFrom'; + const ERROR_COPY_TO = 'errCopyTo'; + const ERROR_COPY_ITSELF = 'errCopyInItself'; + const ERROR_REPLACE = 'errReplace'; // 'Unable to replace "$1".' + const ERROR_RM = 'errRm'; // 'Unable to remove "$1".' + const ERROR_RM_SRC = 'errRmSrc'; // 'Unable remove source file(s)' + const ERROR_UPLOAD = 'errUpload'; // 'Upload error.' + const ERROR_UPLOAD_FILE = 'errUploadFile'; // 'Unable to upload "$1".' + const ERROR_UPLOAD_NO_FILES = 'errUploadNoFiles'; // 'No files found for upload.' + const ERROR_UPLOAD_TOTAL_SIZE = 'errUploadTotalSize'; // 'Data exceeds the maximum allowed size.' + const ERROR_UPLOAD_FILE_SIZE = 'errUploadFileSize'; // 'File exceeds maximum allowed size.' + const ERROR_UPLOAD_FILE_MIME = 'errUploadMime'; // 'File type not allowed.' + const ERROR_UPLOAD_TRANSFER = 'errUploadTransfer'; // '"$1" transfer error.' + // const ERROR_ACCESS_DENIED = 'errAccess'; + const ERROR_NOT_REPLACE = 'errNotReplace'; // Object "$1" already exists at this location and can not be replaced with object of another type. + const ERROR_SAVE = 'errSave'; + const ERROR_EXTRACT = 'errExtract'; + const ERROR_ARCHIVE = 'errArchive'; + const ERROR_NOT_ARCHIVE = 'errNoArchive'; + const ERROR_ARCHIVE_TYPE = 'errArcType'; + const ERROR_ARC_SYMLINKS = 'errArcSymlinks'; + const ERROR_ARC_MAXSIZE = 'errArcMaxSize'; + const ERROR_RESIZE = 'errResize'; + const ERROR_UNSUPPORT_TYPE = 'errUsupportType'; + const ERROR_NOT_UTF8_CONTENT = 'errNotUTF8Content'; + + /** + * Constructor + * + * @param array elFinder and roots configurations + * @return void + * @author Dmitry (dio) Levashov + **/ + public function __construct($opts) { + + $this->time = $this->utime(); + $this->debug = (isset($opts['debug']) && $opts['debug'] ? true : false); + + setlocale(LC_ALL, !empty($opts['locale']) ? $opts['locale'] : 'en_US.UTF-8'); + + // bind events listeners + if (!empty($opts['bind']) && is_array($opts['bind'])) { + foreach ($opts['bind'] as $cmd => $handler) { + $this->bind($cmd, $handler); + } + } + + // "mount" volumes + if (isset($opts['roots']) && is_array($opts['roots'])) { + + foreach ($opts['roots'] as $i => $o) { + $class = 'elFinderVolume'.(isset($o['driver']) ? $o['driver'] : ''); + + if (class_exists($class)) { + $volume = new $class(); + + if ($volume->mount($o)) { + // unique volume id (ends on "_") - used as prefix to files hash + $id = $volume->id(); + + $this->volumes[$id] = $volume; + if (!$this->default && $volume->isReadable()) { + $this->default = $this->volumes[$id]; + } + } else { + $this->mountErrors[] = 'Driver "'.$class.'" : '.implode(' ', $volume->error()); + } + } else { + $this->mountErrors[] = 'Driver "'.$class.'" does not exists'; + } + } + } + // if at least one redable volume - ii desu >_< + $this->loaded = !empty($this->default); + } + + /** + * Return true if fm init correctly + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + public function loaded() { + return $this->loaded; + } + + /** + * Return version (api) number + * + * @return string + * @author Dmitry (dio) Levashov + **/ + public function version() { + return $this->version; + } + + /** + * Add handler to elFinder command + * + * @param string command name + * @param string|array callback name or array(object, method) + * @return elFinder + * @author Dmitry (dio) Levashov + **/ + public function bind($cmd, $handler) { + $cmds = array_map('trim', explode(' ', $cmd)); + + foreach ($cmds as $cmd) { + if ($cmd) { + if (!isset($this->listeners[$cmd])) { + $this->listeners[$cmd] = array(); + } + + if ((is_array($handler) && count($handler) == 2 && is_object($handler[0]) && method_exists($handler[0], $handler[1])) + || function_exists($handler)) { + $this->listeners[$cmd][] = $handler; + } + } + } + + return $this; + } + + /** + * Remove event (command exec) handler + * + * @param string command name + * @param string|array callback name or array(object, method) + * @return elFinder + * @author Dmitry (dio) Levashov + **/ + public function unbind($cmd, $handler) { + if (!empty($this->listeners[$cmd])) { + foreach ($this->listeners[$cmd] as $i => $h) { + if ($h === $handler) { + unset($this->listeners[$cmd][$i]); + return $this; + } + } + } + return $this; + } + + /** + * Return true if command exists + * + * @param string command name + * @return bool + * @author Dmitry (dio) Levashov + **/ + public function commandExists($cmd) { + return $this->loaded && isset($this->commands[$cmd]) && method_exists($this, $cmd); + } + + /** + * Return command required arguments info + * + * @param string command name + * @return array + * @author Dmitry (dio) Levashov + **/ + public function commandArgsList($cmd) { + return $this->commandExists($cmd) ? $this->commands[$cmd] : array(); + } + + /** + * Exec command and return result + * + * @param string $cmd command name + * @param array $args command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + public function exec($cmd, $args) { + + if (!$this->loaded) { + return array('error' => $this->error(self::ERROR_CONF, self::ERROR_CONF_NO_VOL)); + } + + if (!$this->commandExists($cmd)) { + return array('error' => $this->error(self::ERROR_UNKNOWN_CMD)); + } + + if (!empty($args['mimes']) && is_array($args['mimes'])) { + foreach ($this->volumes as $id => $v) { + $this->volumes[$id]->setMimesFilter($args['mimes']); + } + } + + $result = $this->$cmd($args); + + if (isset($result['removed'])) { + foreach ($this->volumes as $volume) { + $result['removed'] = array_merge($result['removed'], $volume->removed()); + $volume->resetRemoved(); + } + } + + // call handlers for this command + if (!empty($this->listeners[$cmd])) { + foreach ($this->listeners[$cmd] as $handler) { + if ((is_array($handler) && $handler[0]->{$handler[1]}($cmd, $result, $args, $this)) + || (!is_array($handler) && $handler($cmd, $result, $args, $this))) { + // handler return true to force sync client after command completed + $result['sync'] = true; + } + } + } + + // replace removed files info with removed files hashes + if (!empty($result['removed'])) { + $removed = array(); + foreach ($result['removed'] as $file) { + $removed[] = $file['hash']; + } + $result['removed'] = array_unique($removed); + } + // remove hidden files and filter files by mimetypes + if (!empty($result['added'])) { + $result['added'] = $this->filter($result['added']); + } + // remove hidden files and filter files by mimetypes + if (!empty($result['changed'])) { + $result['changed'] = $this->filter($result['changed']); + } + + if ($this->debug || !empty($args['debug'])) { + $result['debug'] = array( + 'connector' => 'php', + 'phpver' => PHP_VERSION, + 'time' => $this->utime() - $this->time, + 'memory' => (function_exists('memory_get_peak_usage') ? ceil(memory_get_peak_usage()/1024).'Kb / ' : '').ceil(memory_get_usage()/1024).'Kb / '.ini_get('memory_limit'), + 'upload' => $this->uploadDebug, + 'volumes' => array(), + 'mountErrors' => $this->mountErrors + ); + + foreach ($this->volumes as $id => $volume) { + $result['debug']['volumes'][] = $volume->debug(); + } + } + + foreach ($this->volumes as $volume) { + $volume->umount(); + } + + return $result; + } + + /** + * Return file real path + * + * @param string $hash file hash + * @return string + * @author Dmitry (dio) Levashov + **/ + public function realpath($hash) { + if (($volume = $this->volume($hash)) == false) { + return false; + } + return $volume->realpath($hash); + } + + /***************************************************************************/ + /* commands */ + /***************************************************************************/ + + /** + * Normalize error messages + * + * @return array + * @author Dmitry (dio) Levashov + **/ + public function error() { + $errors = array(); + + foreach (func_get_args() as $msg) { + if (is_array($msg)) { + $errors = array_merge($errors, $msg); + } else { + $errors[] = $msg; + } + } + + return count($errors) ? $errors : array(self::ERROR_UNKNOWN); + } + + /** + * "Open" directory + * Return array with following elements + * - cwd - opened dir info + * - files - opened dir content [and dirs tree if $args[tree]] + * - api - api version (if $args[init]) + * - uplMaxSize - if $args[init] + * - error - on failed + * + * @param array command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function open($args) { + $target = $args['target']; + $init = !empty($args['init']); + $tree = !empty($args['tree']); + $volume = $this->volume($target); + $cwd = $volume ? $volume->dir($target, true) : false; + $hash = $init ? 'default folder' : '#'.$target; + + // on init request we can get invalid dir hash - + // dir which can not be opened now, but remembered by client, + // so open default dir + if ((!$cwd || !$cwd['read']) && $init) { + $volume = $this->default; + $cwd = $volume->dir($volume->defaultPath(), true); + } + + if (!$cwd) { + return array('error' => $this->error(self::ERROR_OPEN, $hash, self::ERROR_DIR_NOT_FOUND)); + } + if (!$cwd['read']) { + return array('error' => $this->error(self::ERROR_OPEN, $hash, self::ERROR_PERM_DENIED)); + } + + $files = array(); + + // get folders trees + if ($args['tree']) { + foreach ($this->volumes as $id => $v) { + + if (($tree = $v->tree('', 0, $cwd['hash'])) != false) { + $files = array_merge($files, $tree); + } + } + } + + // get current working directory files list and add to $files if not exists in it + if (($ls = $volume->scandir($cwd['hash'])) === false) { + return array('error' => $this->error(self::ERROR_OPEN, $cwd['name'], $volume->error())); + } + + foreach ($ls as $file) { + if (!in_array($file, $files)) { + $files[] = $file; + } + } + + $result = array( + 'cwd' => $cwd, + 'options' => $volume->options($cwd['hash']), + 'files' => $files + ); + + if (!empty($args['init'])) { + $result['api'] = $this->version; + $result['uplMaxSize'] = ini_get('upload_max_filesize'); + } + + return $result; + } + + /** + * Return dir files names list + * + * @param array command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function ls($args) { + $target = $args['target']; + + if (($volume = $this->volume($target)) == false + || ($list = $volume->ls($target)) === false) { + return array('error' => $this->error(self::ERROR_OPEN, '#'.$target)); + } + return array('list' => $list); + } + + /** + * Return subdirs for required directory + * + * @param array command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function tree($args) { + $target = $args['target']; + + if (($volume = $this->volume($target)) == false + || ($tree = $volume->tree($target)) == false) { + return array('error' => $this->error(self::ERROR_OPEN, '#'.$target)); + } + + return array('tree' => $tree); + } + + /** + * Return parents dir for required directory + * + * @param array command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function parents($args) { + $target = $args['target']; + + if (($volume = $this->volume($target)) == false + || ($tree = $volume->parents($target)) == false) { + return array('error' => $this->error(self::ERROR_OPEN, '#'.$target)); + } + + return array('tree' => $tree); + } + + /** + * Return new created thumbnails list + * + * @param array command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function tmb($args) { + + $result = array('images' => array()); + $targets = $args['targets']; + + foreach ($targets as $target) { + if (($volume = $this->volume($target)) != false + && (($tmb = $volume->tmb($target)) != false)) { + $result['images'][$target] = $tmb; + } + } + return $result; + } + + /** + * Required to output file in browser when volume URL is not set + * Return array contains opened file pointer, root itself and required headers + * + * @param array command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function file($args) { + $target = $args['target']; + $download = !empty($args['download']); + $h403 = 'HTTP/1.x 403 Access Denied'; + $h404 = 'HTTP/1.x 404 Not Found'; + + if (($volume = $this->volume($target)) == false) { + return array('error' => 'File not found', 'header' => $h404, 'raw' => true); + } + + if (($file = $volume->file($target)) == false) { + return array('error' => 'File not found', 'header' => $h404, 'raw' => true); + } + + if (!$file['read']) { + return array('error' => 'Access denied', 'header' => $h403, 'raw' => true); + } + + if (($fp = $volume->open($target)) == false) { + return array('error' => 'File not found', 'header' => $h404, 'raw' => true); + } + + if ($download) { + $disp = 'attachment'; + $mime = 'application/octet-stream'; + } else { + $disp = preg_match('/^(image|text)/i', $file['mime']) || $file['mime'] == 'application/x-shockwave-flash' + ? 'inline' + : 'attachment'; + $mime = $file['mime']; + } + + $filenameEncoded = rawurlencode($file['name']); + if (strpos($filenameEncoded, '%') === false) { // ASCII only + $filename = 'filename="'.$file['name'].'"'; + } else { + $ua = $_SERVER["HTTP_USER_AGENT"]; + if (preg_match('/MSIE [4-8]/', $ua)) { // IE < 9 do not support RFC 6266 (RFC 2231/RFC 5987) + $filename = 'filename="'.$filenameEncoded.'"'; + } else { // RFC 6266 (RFC 2231/RFC 5987) + $filename = 'filename*=UTF-8\'\''.$filenameEncoded; + } + } + + $result = array( + 'volume' => $volume, + 'pointer' => $fp, + 'info' => $file, + 'header' => array( + 'Content-Type: '.$mime, + 'Content-Disposition: '.$disp.'; '.$filename, + 'Content-Location: '.$file['name'], + 'Content-Transfer-Encoding: binary', + 'Content-Length: '.$file['size'], + 'Connection: close' + ) + ); + return $result; + } + + /** + * Count total files size + * + * @param array command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function size($args) { + $size = 0; + + foreach ($args['targets'] as $target) { + if (($volume = $this->volume($target)) == false + || ($file = $volume->file($target)) == false + || !$file['read']) { + return array('error' => $this->error(self::ERROR_OPEN, '#'.$target)); + } + + $size += $volume->size($target); + } + return array('size' => $size); + } + + /** + * Create directory + * + * @param array command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function mkdir($args) { + $target = $args['target']; + $name = $args['name']; + + if (($volume = $this->volume($target)) == false) { + return array('error' => $this->error(self::ERROR_MKDIR, $name, self::ERROR_TRGDIR_NOT_FOUND, '#'.$target)); + } + + return ($dir = $volume->mkdir($target, $name)) == false + ? array('error' => $this->error(self::ERROR_MKDIR, $name, $volume->error())) + : array('added' => array($dir)); + } + + /** + * Create empty file + * + * @param array command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function mkfile($args) { + $target = $args['target']; + $name = $args['name']; + + if (($volume = $this->volume($target)) == false) { + return array('error' => $this->error(self::ERROR_MKFILE, $name, self::ERROR_TRGDIR_NOT_FOUND, '#'.$target)); + } + + return ($file = $volume->mkfile($target, $args['name'])) == false + ? array('error' => $this->error(self::ERROR_MKFILE, $name, $volume->error())) + : array('added' => array($file)); + } + + /** + * Rename file + * + * @param array $args + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function rename($args) { + $target = $args['target']; + $name = $args['name']; + + if (($volume = $this->volume($target)) == false + || ($rm = $volume->file($target)) == false) { + return array('error' => $this->error(self::ERROR_RENAME, '#'.$target, self::ERROR_FILE_NOT_FOUND)); + } + $rm['realpath'] = $volume->realpath($target); + + return ($file = $volume->rename($target, $name)) == false + ? array('error' => $this->error(self::ERROR_RENAME, $rm['name'], $volume->error())) + : array('added' => array($file), 'removed' => array($rm)); + } + + /** + * Duplicate file - create copy with "copy %d" suffix + * + * @param array $args command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function duplicate($args) { + $targets = is_array($args['targets']) ? $args['targets'] : array(); + $result = array('added' => array()); + $suffix = empty($args['suffix']) ? 'copy' : $args['suffix']; + + foreach ($targets as $target) { + if (($volume = $this->volume($target)) == false + || ($src = $volume->file($target)) == false) { + $result['warning'] = $this->error(self::ERROR_COPY, '#'.$target, self::ERROR_FILE_NOT_FOUND); + break; + } + + if (($file = $volume->duplicate($target, $suffix)) == false) { + $result['warning'] = $this->error($volume->error()); + break; + } + + $result['added'][] = $file; + } + + return $result; + } + + /** + * Remove dirs/files + * + * @param array command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function rm($args) { + $targets = is_array($args['targets']) ? $args['targets'] : array(); + $result = array('removed' => array()); + + foreach ($targets as $target) { + if (($volume = $this->volume($target)) == false) { + $result['warning'] = $this->error(self::ERROR_RM, '#'.$target, self::ERROR_FILE_NOT_FOUND); + return $result; + } + if (!$volume->rm($target)) { + $result['warning'] = $this->error($volume->error()); + return $result; + } + } + + return $result; + } + + /** + * Save uploaded files + * + * @param array + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function upload($args) { + $target = $args['target']; + $volume = $this->volume($target); + $files = isset($args['FILES']['upload']) && is_array($args['FILES']['upload']) ? $args['FILES']['upload'] : array(); + $result = array('added' => array(), 'header' => empty($args['html']) ? false : 'Content-Type: text/html; charset=utf-8'); + + if (empty($files)) { + return array('error' => $this->error(self::ERROR_UPLOAD, self::ERROR_UPLOAD_NO_FILES), 'header' => $header); + } + + if (!$volume) { + return array('error' => $this->error(self::ERROR_UPLOAD, self::ERROR_TRGDIR_NOT_FOUND, '#'.$target), 'header' => $header); + } + + foreach ($files['name'] as $i => $name) { + if (($error = $files['error'][$i]) > 0) { + $result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, $error == UPLOAD_ERR_INI_SIZE || $error == UPLOAD_ERR_FORM_SIZE ? self::ERROR_UPLOAD_FILE_SIZE : self::ERROR_UPLOAD_TRANSFER); + $this->uploadDebug = 'Upload error code: '.$error; + break; + } + + $tmpname = $files['tmp_name'][$i]; + + if (($fp = fopen($tmpname, 'rb')) == false) { + $result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, self::ERROR_UPLOAD_TRANSFER); + $this->uploadDebug = 'Upload error: unable open tmp file'; + break; + } + + if (($file = $volume->upload($fp, $target, $name, $tmpname)) === false) { + $result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, $volume->error()); + fclose($fp); + break; + } + + fclose($fp); + $result['added'][] = $file; + } + + return $result; + } + + /** + * Copy/move files into new destination + * + * @param array command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function paste($args) { + $dst = $args['dst']; + $targets = is_array($args['targets']) ? $args['targets'] : array(); + $cut = !empty($args['cut']); + $error = $cut ? self::ERROR_MOVE : self::ERROR_COPY; + $result = array('added' => array(), 'removed' => array()); + + if (($dstVolume = $this->volume($dst)) == false) { + return array('error' => $this->error($error, '#'.$targets[0], self::ERROR_TRGDIR_NOT_FOUND, '#'.$dst)); + } + + foreach ($targets as $target) { + if (($srcVolume = $this->volume($target)) == false) { + $result['warning'] = $this->error($error, '#'.$target, self::ERROR_FILE_NOT_FOUND); + break; + } + + if (($file = $dstVolume->paste($srcVolume, $target, $dst, $cut)) == false) { + $result['warning'] = $this->error($dstVolume->error()); + break; + } + + $result['added'][] = $file; + } + return $result; + } + + /** + * Return file content + * + * @param array $args command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function get($args) { + $target = $args['target']; + $volume = $this->volume($target); + + if (!$volume || ($file = $volume->file($target)) == false) { + return array('error' => $this->error(self::ERROR_OPEN, '#'.$target, self::ERROR_FILE_NOT_FOUND)); + } + + if (($content = $volume->getContents($target)) === false) { + return array('error' => $this->error(self::ERROR_OPEN, $volume->path($target), $volume->error())); + } + + $json = json_encode($content); + + if ($json == 'null' && strlen($json) < strlen($content)) { + return array('error' => $this->error(self::ERROR_NOT_UTF8_CONTENT, $volume->path($target))); + } + + return array('content' => $content); + } + + /** + * Save content into text file + * + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function put($args) { + $target = $args['target']; + + if (($volume = $this->volume($target)) == false + || ($file = $volume->file($target)) == false) { + return array('error' => $this->error(self::ERROR_SAVE, '#'.$target, self::ERROR_FILE_NOT_FOUND)); + } + + if (($file = $volume->putContents($target, $args['content'])) == false) { + return array('error' => $this->error(self::ERROR_SAVE, $volume->path($target), $volume->error())); + } + + return array('changed' => array($file)); + } + + /** + * Extract files from archive + * + * @param array $args command arguments + * @return array + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function extract($args) { + $target = $args['target']; + $mimes = !empty($args['mimes']) && is_array($args['mimes']) ? $args['mimes'] : array(); + $error = array(self::ERROR_EXTRACT, '#'.$target); + + if (($volume = $this->volume($target)) == false + || ($file = $volume->file($target)) == false) { + return array('error' => $this->error(self::ERROR_EXTRACT, '#'.$target, self::ERROR_FILE_NOT_FOUND)); + } + + return ($file = $volume->extract($target)) + ? array('added' => array($file)) + : array('error' => $this->error(self::ERROR_EXTRACT, $volume->path($target), $volume->error())); + } + + /** + * Create archive + * + * @param array $args command arguments + * @return array + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function archive($args) { + $type = $args['type']; + $targets = isset($args['targets']) && is_array($args['targets']) ? $args['targets'] : array(); + + if (($volume = $this->volume($targets[0])) == false) { + return $this->error(self::ERROR_ARCHIVE, self::ERROR_TRGDIR_NOT_FOUND); + } + + return ($file = $volume->archive($targets, $args['type'])) + ? array('added' => array($file)) + : array('error' => $this->error(self::ERROR_ARCHIVE, $volume->error())); + } + + /** + * Search files + * + * @param array $args command arguments + * @return array + * @author Dmitry Levashov + **/ + protected function search($args) { + $q = trim($args['q']); + $mimes = !empty($args['mimes']) && is_array($args['mimes']) ? $args['mimes'] : array(); + $result = array(); + + foreach ($this->volumes as $volume) { + $result = array_merge($result, $volume->search($q, $mimes)); + } + + return array('files' => $result); + } + + /** + * Return file info (used by client "places" ui) + * + * @param array $args command arguments + * @return array + * @author Dmitry Levashov + **/ + protected function info($args) { + $files = array(); + + foreach ($args['targets'] as $hash) { + if (($volume = $this->volume($hash)) != false + && ($info = $volume->file($hash)) != false) { + $files[] = $info; + } + } + + return array('files' => $files); + } + + /** + * Return image dimmensions + * + * @param array $args command arguments + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function dim($args) { + $target = $args['target']; + + if (($volume = $this->volume($target)) != false) { + $dim = $volume->dimensions($target); + return $dim ? array('dim' => $dim) : array(); + } + return array(); + } + + /** + * Resize image + * + * @param array command arguments + * @return array + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + **/ + protected function resize($args) { + $target = $args['target']; + $width = $args['width']; + $height = $args['height']; + $x = (int)$args['x']; + $y = (int)$args['y']; + $mode = $args['mode']; + $bg = null; + $degree = (int)$args['degree']; + + if (($volume = $this->volume($target)) == false + || ($file = $volume->file($target)) == false) { + return array('error' => $this->error(self::ERROR_RESIZE, '#'.$target, self::ERROR_FILE_NOT_FOUND)); + } + + return ($file = $volume->resize($target, $width, $height, $x, $y, $mode, $bg, $degree)) + ? array('changed' => array($file)) + : array('error' => $this->error(self::ERROR_RESIZE, $volume->path($target), $volume->error())); + } + + /***************************************************************************/ + /* utils */ + /***************************************************************************/ + + /** + * Return root - file's owner + * + * @param string file hash + * @return elFinderStorageDriver + * @author Dmitry (dio) Levashov + **/ + protected function volume($hash) { + foreach ($this->volumes as $id => $v) { + if (strpos(''.$hash, $id) === 0) { + return $this->volumes[$id]; + } + } + return false; + } + + /** + * Return files info array + * + * @param array $data one file info or files info + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function toArray($data) { + return isset($data['hash']) || !is_array($data) ? array($data) : $data; + } + + /** + * Return fils hashes list + * + * @param array $files files info + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function hashes($files) { + $ret = array(); + foreach ($files as $file) { + $ret[] = $file['hash']; + } + return $ret; + } + + /** + * Remove from files list hidden files and files with required mime types + * + * @param array $files files info + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function filter($files) { + foreach ($files as $i => $file) { + if (!empty($file['hidden']) || !$this->default->mimeAccepted($file['mime'])) { + unset($files[$i]); + } + } + return array_merge($files, array()); + } + + protected function utime() { + $time = explode(" ", microtime()); + return (double)$time[1] + (double)$time[0]; + } + +} // END class diff --git a/administrator/components/com_k2/lib/elfinder/elFinderConnector.class.php b/administrator/components/com_k2/lib/elfinder/elFinderConnector.class.php new file mode 100644 index 0000000..3b51db4 --- /dev/null +++ b/administrator/components/com_k2/lib/elfinder/elFinderConnector.class.php @@ -0,0 +1,143 @@ +elFinder = $elFinder; + if ($debug) { + $this->header = 'Content-Type: text/html; charset=utf-8'; + } + } + + /** + * Execute elFinder command and output result + * + * @return void + * @author Dmitry (dio) Levashov + **/ + public function run() { + $isPost = $_SERVER["REQUEST_METHOD"] == 'POST'; + $src = $_SERVER["REQUEST_METHOD"] == 'POST' ? $_POST : $_GET; + $cmd = isset($src['cmd']) ? $src['cmd'] : ''; + $args = array(); + + if (!function_exists('json_encode')) { + $error = $this->elFinder->error(elFinder::ERROR_CONF, elFinder::ERROR_CONF_NO_JSON); + $this->output(array('error' => '{"error":["'.implode('","', $error).'"]}', 'raw' => true)); + } + + if (!$this->elFinder->loaded()) { + $this->output(array('error' => $this->elFinder->error(elFinder::ERROR_CONF, elFinder::ERROR_CONF_NO_VOL), 'debug' => $this->elFinder->mountErrors)); + } + + // telepat_mode: on + if (!$cmd && $isPost) { + $this->output(array('error' => $this->elFinder->error(elFinder::ERROR_UPLOAD, elFinder::ERROR_UPLOAD_TOTAL_SIZE), 'header' => 'Content-Type: text/html')); + } + // telepat_mode: off + + if (!$this->elFinder->commandExists($cmd)) { + $this->output(array('error' => $this->elFinder->error(elFinder::ERROR_UNKNOWN_CMD))); + } + + // collect required arguments to exec command + foreach ($this->elFinder->commandArgsList($cmd) as $name => $req) { + $arg = $name == 'FILES' + ? $_FILES + : (isset($src[$name]) ? $src[$name] : ''); + + if (!is_array($arg)) { + $arg = trim($arg); + } + if ($req && (!isset($arg) || $arg === '')) { + $this->output(array('error' => $this->elFinder->error(elFinder::ERROR_INV_PARAMS, $cmd))); + } + $args[$name] = $arg; + } + + $args['debug'] = isset($src['debug']) ? !!$src['debug'] : false; + + $this->output($this->elFinder->exec($cmd, $args)); + } + + /** + * Output json + * + * @param array data to output + * @return void + * @author Dmitry (dio) Levashov + **/ + protected function output(array $data) { + $header = isset($data['header']) ? $data['header'] : $this->header; + unset($data['header']); + if ($header) { + if (is_array($header)) { + foreach ($header as $h) { + header($h); + } + } else { + header($header); + } + } + + if (isset($data['pointer'])) { + rewind($data['pointer']); + fpassthru($data['pointer']); + if (!empty($data['volume'])) { + $data['volume']->close($data['pointer'], $data['info']['hash']); + } + exit(); + } else { + if (!empty($data['raw']) && !empty($data['error'])) { + exit($data['error']); + } else { + exit(json_encode($data)); + } + } + + } + +}// END class diff --git a/administrator/components/com_k2/lib/elfinder/elFinderVolumeDriver.class.php b/administrator/components/com_k2/lib/elfinder/elFinderVolumeDriver.class.php new file mode 100644 index 0000000..48bd7e5 --- /dev/null +++ b/administrator/components/com_k2/lib/elfinder/elFinderVolumeDriver.class.php @@ -0,0 +1,3381 @@ + array(), + 'extract' => array() + ); + + /** + * How many subdirs levels return for tree + * + * @var int + **/ + protected $treeDeep = 1; + + /** + * Errors from last failed action + * + * @var array + **/ + protected $error = array(); + + /** + * Today 24:00 timestamp + * + * @var int + **/ + protected $today = 0; + + /** + * Yesterday 24:00 timestamp + * + * @var int + **/ + protected $yesterday = 0; + + /** + * Object configuration + * + * @var array + **/ + protected $options = array( + 'id' => '', + // root directory path + 'path' => '', + // open this path on initial request instead of root path + 'startPath' => '', + // how many subdirs levels return per request + 'treeDeep' => 1, + // root url, not set to disable sending URL to client (replacement for old "fileURL" option) + 'URL' => '', + // directory separator. required by client to show paths correctly + 'separator' => DIRECTORY_SEPARATOR, + // library to crypt/uncrypt files names (not implemented) + 'cryptLib' => '', + // how to detect files mimetypes. (auto/internal/finfo/mime_content_type) + 'mimeDetect' => 'auto', + // mime.types file path (for mimeDetect==internal) + 'mimefile' => '', + // directory for thumbnails + 'tmbPath' => '.tmb', + // mode to create thumbnails dir + 'tmbPathMode' => 0755, + // thumbnails dir URL. Set it if store thumbnails outside root directory + 'tmbURL' => '', + // thumbnails size (px) + 'tmbSize' => 48, + // thumbnails crop (true - crop, false - scale image to fit thumbnail size) + 'tmbCrop' => true, + // thumbnails background color (hex #rrggbb or 'transparent') + 'tmbBgColor' => '#ffffff', + // image manipulations library + 'imgLib' => 'auto', + // on paste file - if true - old file will be replaced with new one, if false new file get name - original_name-number.ext + 'copyOverwrite' => true, + // if true - join new and old directories content on paste + 'copyJoin' => true, + // on upload - if true - old file will be replaced with new one, if false new file get name - original_name-number.ext + 'uploadOverwrite' => true, + // mimetypes allowed to upload + 'uploadAllow' => array(), + // mimetypes not allowed to upload + 'uploadDeny' => array(), + // order to proccess uploadAllow and uploadDeny options + 'uploadOrder' => array('deny', 'allow'), + // maximum upload file size. NOTE - this is size for every uploaded files + 'uploadMaxSize' => 0, + // files dates format + 'dateFormat' => 'j M Y H:i', + // files time format + 'timeFormat' => 'H:i', + // if true - every folder will be check for children folders, otherwise all folders will be marked as having subfolders + 'checkSubfolders' => true, + // allow to copy from this volume to other ones? + 'copyFrom' => true, + // allow to copy from other volumes to this one? + 'copyTo' => true, + // list of commands disabled on this root + 'disabled' => array(), + // regexp or function name to validate new file name + 'acceptedName' => '/^\w[\w\s\.\%\-\(\)\[\]]*$/u', + // function/class method to control files permissions + 'accessControl' => null, + // some data required by access control + 'accessControlData' => null, + // default permissions. not set hidden/locked here - take no effect + 'defaults' => array( + 'read' => true, + 'write' => true + ), + // files attributes + 'attributes' => array(), + // Allowed archive's mimetypes to create. Leave empty for all available types. + 'archiveMimes' => array(), + // Manual config for archivers. See example below. Leave empty for auto detect + 'archivers' => array(), + // required to fix bug on macos + 'utf8fix' => false, + // й ё Й Ё Ø Å + 'utf8patterns' => array("\u0438\u0306", "\u0435\u0308", "\u0418\u0306", "\u0415\u0308", "\u00d8A", "\u030a"), + 'utf8replace' => array("\u0439", "\u0451", "\u0419", "\u0401", "\u00d8", "\u00c5") + ); + + /** + * Defaults permissions + * + * @var array + **/ + protected $defaults = array( + 'read' => true, + 'write' => true, + 'locked' => false, + 'hidden' => false + ); + + /** + * Access control function/class + * + * @var mixed + **/ + protected $attributes = array(); + + /** + * Access control function/class + * + * @var mixed + **/ + protected $access = null; + + /** + * Mime types allowed to upload + * + * @var array + **/ + protected $uploadAllow = array(); + + /** + * Mime types denied to upload + * + * @var array + **/ + protected $uploadDeny = array(); + + /** + * Order to validate uploadAllow and uploadDeny + * + * @var array + **/ + protected $uploadOrder = array(); + + /** + * Maximum allowed upload file size. + * Set as number or string with unit - "10M", "500K", "1G" + * + * @var int|string + **/ + protected $uploadMaxSize = 0; + + /** + * Mimetype detect method + * + * @var string + **/ + protected $mimeDetect = 'auto'; + + /** + * Flag - mimetypes from externail file was loaded + * + * @var bool + **/ + private static $mimetypesLoaded = false; + + /** + * Finfo object for mimeDetect == 'finfo' + * + * @var object + **/ + protected $finfo = null; + + /** + * List of disabled client's commands + * + * @var array + **/ + protected $diabled = array(); + + /** + * default extensions/mimetypes for mimeDetect == 'internal' + * + * @var array + **/ + protected static $mimetypes = array( + // applications + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'exe' => 'application/x-executable', + 'doc' => 'application/vnd.ms-word', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pps' => 'application/vnd.ms-powerpoint', + 'pdf' => 'application/pdf', + 'xml' => 'application/xml', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'swf' => 'application/x-shockwave-flash', + 'torrent' => 'application/x-bittorrent', + 'jar' => 'application/x-jar', + // archives + 'gz' => 'application/x-gzip', + 'tgz' => 'application/x-gzip', + 'bz' => 'application/x-bzip2', + 'bz2' => 'application/x-bzip2', + 'tbz' => 'application/x-bzip2', + 'zip' => 'application/zip', + 'rar' => 'application/x-rar', + 'tar' => 'application/x-tar', + '7z' => 'application/x-7z-compressed', + // texts + 'txt' => 'text/plain', + 'php' => 'text/x-php', + 'html' => 'text/html', + 'htm' => 'text/html', + 'js' => 'text/javascript', + 'css' => 'text/css', + 'rtf' => 'text/rtf', + 'rtfd' => 'text/rtfd', + 'py' => 'text/x-python', + 'java' => 'text/x-java-source', + 'rb' => 'text/x-ruby', + 'sh' => 'text/x-shellscript', + 'pl' => 'text/x-perl', + 'xml' => 'text/xml', + 'sql' => 'text/x-sql', + 'c' => 'text/x-csrc', + 'h' => 'text/x-chdr', + 'cpp' => 'text/x-c++src', + 'hh' => 'text/x-c++hdr', + 'log' => 'text/plain', + 'csv' => 'text/x-comma-separated-values', + // images + 'bmp' => 'image/x-ms-bmp', + 'jpg' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'gif' => 'image/gif', + 'png' => 'image/png', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'tga' => 'image/x-targa', + 'psd' => 'image/vnd.adobe.photoshop', + 'ai' => 'image/vnd.adobe.photoshop', + 'xbm' => 'image/xbm', + 'pxm' => 'image/pxm', + //audio + 'mp3' => 'audio/mpeg', + 'mid' => 'audio/midi', + 'ogg' => 'audio/ogg', + 'oga' => 'audio/ogg', + 'm4a' => 'audio/x-m4a', + 'wav' => 'audio/wav', + 'wma' => 'audio/x-ms-wma', + // video + 'avi' => 'video/x-msvideo', + 'dv' => 'video/x-dv', + 'mp4' => 'video/mp4', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mov' => 'video/quicktime', + 'wm' => 'video/x-ms-wmv', + 'flv' => 'video/x-flv', + 'mkv' => 'video/x-matroska', + 'webm' => 'video/webm', + 'ogv' => 'video/ogg', + 'ogm' => 'video/ogg' + ); + + /** + * Directory separator - required by client + * + * @var string + **/ + protected $separator = DIRECTORY_SEPARATOR; + + /** + * Mimetypes allowed to display + * + * @var array + **/ + protected $onlyMimes = array(); + + /** + * Store files moved or overwrited files info + * + * @var array + **/ + protected $removed = array(); + + /** + * Cache storage + * + * @var array + **/ + protected $cache = array(); + + /** + * Cache by folders + * + * @var array + **/ + protected $dirsCache = array(); + + /*********************************************************************/ + /* INITIALIZATION */ + /*********************************************************************/ + + /** + * Prepare driver before mount volume. + * Return true if volume is ready. + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function init() { + return true; + } + + /** + * Configure after successfull mount. + * By default set thumbnails path and image manipulation library. + * + * @return void + * @author Dmitry (dio) Levashov + **/ + protected function configure() { + // set thumbnails path + $path = $this->options['tmbPath']; + if ($path) { + if (!file_exists($path)) { + if (@mkdir($path)) { + chmod($path, $this->options['tmbPathMode']); + } else { + $path = ''; + } + } + + if (is_dir($path) && is_readable($path)) { + $this->tmbPath = $path; + $this->tmbPathWritable = is_writable($path); + } + } + + // set image manipulation library + $type = preg_match('/^(imagick|gd|auto)$/i', $this->options['imgLib']) + ? strtolower($this->options['imgLib']) + : 'auto'; + + if (($type == 'imagick' || $type == 'auto') && extension_loaded('imagick')) { + $this->imgLib = 'imagick'; + } else { + $this->imgLib = function_exists('gd_info') ? 'gd' : ''; + } + + } + + + /*********************************************************************/ + /* PUBLIC API */ + /*********************************************************************/ + + /** + * Return driver id. Used as a part of volume id. + * + * @return string + * @author Dmitry (dio) Levashov + **/ + public function driverId() { + return $this->driverId; + } + + /** + * Return volume id + * + * @return string + * @author Dmitry (dio) Levashov + **/ + public function id() { + return $this->id; + } + + /** + * Return debug info for client + * + * @return array + * @author Dmitry (dio) Levashov + **/ + public function debug() { + return array( + 'id' => $this->id(), + 'name' => strtolower(substr(get_class($this), strlen('elfinderdriver'))), + 'mimeDetect' => $this->mimeDetect, + 'imgLib' => $this->imgLib + ); + } + + /** + * "Mount" volume. + * Return true if volume available for read or write, + * false - otherwise + * + * @return bool + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + **/ + public function mount(array $opts) { + if (!isset($opts['path']) || $opts['path'] === '') { + return false; + } + + $this->options = array_merge($this->options, $opts); + $this->id = $this->driverId.(!empty($this->options['id']) ? $this->options['id'] : elFinder::$volumesCnt++).'_'; + $this->root = $this->_normpath($this->options['path']); + $this->separator = isset($this->options['separator']) ? $this->options['separator'] : DIRECTORY_SEPARATOR; + + // default file attribute + $this->defaults = array( + 'read' => isset($this->options['defaults']['read']) ? !!$this->options['defaults']['read'] : true, + 'write' => isset($this->options['defaults']['write']) ? !!$this->options['defaults']['write'] : true, + 'locked' => false, + 'hidden' => false + ); + + // root attributes + $this->attributes[] = array( + 'pattern' => '~^'.preg_quote(DIRECTORY_SEPARATOR).'$~', + 'locked' => true, + 'hidden' => false + ); + // set files attributes + if (!empty($this->options['attributes']) && is_array($this->options['attributes'])) { + + foreach ($this->options['attributes'] as $a) { + // attributes must contain pattern and at least one rule + if (!empty($a['pattern']) || count($a) > 1) { + $this->attributes[] = $a; + } + } + } + + if (!empty($this->options['accessControl'])) { + if (is_string($this->options['accessControl']) + && function_exists($this->options['accessControl'])) { + $this->access = $this->options['accessControl']; + } elseif (is_array($this->options['accessControl']) + && count($this->options['accessControl']) > 1 + && is_object($this->options['accessControl'][0]) + && method_exists($this->options['accessControl'][0], $this->options['accessControl'][1])) { + $this->access = array($this->options['accessControl'][0], $this->options['accessControl'][1]); + } + } + + $this->today = mktime(0,0,0, date('m'), date('d'), date('Y')); + $this->yesterday = $this->today-86400; + + // debug($this->attributes); + if (!$this->init()) { + return false; + } + + // check some options is arrays + $this->uploadAllow = isset($this->options['uploadAllow']) && is_array($this->options['uploadAllow']) + ? $this->options['uploadAllow'] + : array(); + + $this->uploadDeny = isset($this->options['uploadDeny']) && is_array($this->options['uploadDeny']) + ? $this->options['uploadDeny'] + : array(); + + if (is_string($this->options['uploadOrder'])) { // telephat_mode on, compatibility with 1.x + $parts = explode(',', isset($this->options['uploadOrder']) ? $this->options['uploadOrder'] : 'deny,allow'); + $this->uploadOrder = array(trim($parts[0]), trim($parts[1])); + } else { // telephat_mode off + $this->uploadOrder = $this->options['uploadOrder']; + } + + if (!empty($this->options['uploadMaxSize'])) { + $size = ''.$this->options['uploadMaxSize']; + $unit = strtolower(substr($size, strlen($size) - 1)); + $n = 1; + switch ($unit) { + case 'k': + $n = 1024; + break; + case 'm': + $n = 1048576; + break; + case 'g': + $n = 1073741824; + } + $this->uploadMaxSize = intval($size)*$n; + } + + $this->disabled = isset($this->options['disabled']) && is_array($this->options['disabled']) + ? $this->options['disabled'] + : array(); + + $this->cryptLib = $this->options['cryptLib']; + $this->mimeDetect = $this->options['mimeDetect']; + + // find available mimetype detect method + $type = strtolower($this->options['mimeDetect']); + $type = preg_match('/^(finfo|mime_content_type|internal|auto)$/i', $type) ? $type : 'auto'; + $regexp = '/text\/x\-(php|c\+\+)/'; + + if (($type == 'finfo' || $type == 'auto') + && class_exists('finfo') + && @preg_match($regexp, array_shift(explode(';', @finfo_file(finfo_open(FILEINFO_MIME), __FILE__))))) { + $type = 'finfo'; + $this->finfo = finfo_open(FILEINFO_MIME); + } elseif (($type == 'mime_content_type' || $type == 'auto') + && function_exists('mime_content_type') + && preg_match($regexp, array_shift(explode(';', mime_content_type(__FILE__))))) { + $type = 'mime_content_type'; + } else { + $type = 'internal'; + } + $this->mimeDetect = $type; + + // load mimes from external file for mimeDetect == 'internal' + // based on Alexey Sukhotin idea and patch: http://elrte.org/redmine/issues/163 + // file must be in file directory or in parent one + if ($this->mimeDetect == 'internal' && !self::$mimetypesLoaded) { + self::$mimetypesLoaded = true; + $this->mimeDetect = 'internal'; + $file = false; + if (!empty($this->options['mimefile']) && file_exists($this->options['mimefile'])) { + $file = $this->options['mimefile']; + } elseif (file_exists(dirname(__FILE__).DIRECTORY_SEPARATOR.'mime.types')) { + $file = dirname(__FILE__).DIRECTORY_SEPARATOR.'mime.types'; + } elseif (file_exists(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'mime.types')) { + $file = dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'mime.types'; + } + + if ($file && file_exists($file)) { + $mimecf = file($file); + + foreach ($mimecf as $line_num => $line) { + if (!preg_match('/^\s*#/', $line)) { + $mime = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY); + for ($i = 1, $size = count($mime); $i < $size ; $i++) { + if (!isset(self::$mimetypes[$mime[$i]])) { + self::$mimetypes[$mime[$i]] = $mime[0]; + } + } + } + } + } + } + + $this->rootName = empty($this->options['alias']) ? $this->_basename($this->root) : $this->options['alias']; + $root = $this->stat($this->root); + + if (!$root) { + return $this->setError('Root folder does not exists.'); + } + if (!$root['read'] && !$root['write']) { + return $this->setError('Root folder has not read and write permissions.'); + } + + // debug($root); + + if ($root['read']) { + // check startPath - path to open by default instead of root + if ($this->options['startPath']) { + $start = $this->stat($this->options['startPath']); + if (!empty($start) + && $start['mime'] == 'directory' + && $start['read'] + && empty($start['hidden']) + && $this->_inpath($this->options['startPath'], $this->root)) { + $this->startPath = $this->options['startPath']; + if (substr($this->startPath, -1, 1) == $this->options['separator']) { + $this->startPath = substr($this->startPath, 0, -1); + } + } + } + } else { + $this->options['URL'] = ''; + $this->options['tmbURL'] = ''; + $this->options['tmbPath'] = ''; + // read only volume + array_unshift($this->attributes, array( + 'pattern' => '/.*/', + 'read' => false + )); + } + $this->treeDeep = $this->options['treeDeep'] > 0 ? (int)$this->options['treeDeep'] : 1; + $this->tmbSize = $this->options['tmbSize'] > 0 ? (int)$this->options['tmbSize'] : 48; + $this->URL = $this->options['URL']; + if ($this->URL && preg_match("|[^/?&=]$|", $this->URL)) { + $this->URL .= '/'; + } + + $this->tmbURL = !empty($this->options['tmbURL']) ? $this->options['tmbURL'] : ''; + if ($this->tmbURL && preg_match("|[^/?&=]$|", $this->tmbURL)) { + $this->tmbURL .= '/'; + } + + $this->nameValidator = is_string($this->options['acceptedName']) && !empty($this->options['acceptedName']) + ? $this->options['acceptedName'] + : ''; + + $this->_checkArchivers(); + // manual control archive types to create + if (!empty($this->options['archiveMimes']) && is_array($this->options['archiveMimes'])) { + foreach ($this->archivers['create'] as $mime => $v) { + if (!in_array($mime, $this->options['archiveMimes'])) { + unset($this->archivers['create'][$mime]); + } + } + } + + // manualy add archivers + if (!empty($this->options['archivers']['create']) && is_array($this->options['archivers']['create'])) { + foreach ($this->options['archivers']['create'] as $mime => $conf) { + if (strpos($mime, 'application/') === 0 + && !empty($conf['cmd']) + && isset($conf['argc']) + && !empty($conf['ext']) + && !isset($this->archivers['create'][$mime])) { + $this->archivers['create'][$mime] = $conf; + } + } + } + + if (!empty($this->options['archivers']['extract']) && is_array($this->options['archivers']['extract'])) { + foreach ($this->options['archivers']['extract'] as $mime => $conf) { + if (substr($mime, 'application/') === 0 + && !empty($cons['cmd']) + && isset($conf['argc']) + && !empty($conf['ext']) + && !isset($this->archivers['extract'][$mime])) { + $this->archivers['extract'][$mime] = $conf; + } + } + } + + $this->configure(); + // echo $this->uploadMaxSize; + // echo $this->options['uploadMaxSize']; + return $this->mounted = true; + } + + /** + * Some "unmount" stuffs - may be required by virtual fs + * + * @return void + * @author Dmitry (dio) Levashov + **/ + public function umount() { + } + + /** + * Return error message from last failed action + * + * @return array + * @author Dmitry (dio) Levashov + **/ + public function error() { + return $this->error; + } + + /** + * Set mimetypes allowed to display to client + * + * @param array $mimes + * @return void + * @author Dmitry (dio) Levashov + **/ + public function setMimesFilter($mimes) { + if (is_array($mimes)) { + $this->onlyMimes = $mimes; + } + } + + /** + * Return root folder hash + * + * @return string + * @author Dmitry (dio) Levashov + **/ + public function root() { + return $this->encode($this->root); + } + + /** + * Return root or startPath hash + * + * @return string + * @author Dmitry (dio) Levashov + **/ + public function defaultPath() { + return $this->encode($this->startPath ? $this->startPath : $this->root); + } + + /** + * Return volume options required by client: + * + * @return array + * @author Dmitry (dio) Levashov + **/ + public function options($hash) { + return array( + 'path' => $this->_path($this->decode($hash)), + 'url' => $this->URL, + 'tmbUrl' => $this->tmbURL, + 'disabled' => $this->disabled, + 'separator' => $this->separator, + 'copyOverwrite' => intval($this->options['copyOverwrite']), + 'archivers' => array( + 'create' => array_keys($this->archivers['create']), + 'extract' => array_keys($this->archivers['extract']) + ) + ); + } + + /** + * Return true if command disabled in options + * + * @param string $cmd command name + * @return bool + * @author Dmitry (dio) Levashov + **/ + public function commandDisabled($cmd) { + return in_array($cmd, $this->disabled); + } + + /** + * Return true if mime is required mimes list + * + * @param string $mime mime type to check + * @param array $mimes allowed mime types list or not set to use client mimes list + * @param bool|null $empty what to return on empty list + * @return bool|null + * @author Dmitry (dio) Levashov + * @author Troex Nevelin + **/ + public function mimeAccepted($mime, $mimes = array(), $empty = true) { + $mimes = !empty($mimes) ? $mimes : $this->onlyMimes; + if (empty($mimes)) { + return $empty; + } + return $mime == 'directory' + || in_array('all', $mimes) + || in_array('All', $mimes) + || in_array($mime, $mimes) + || in_array(substr($mime, 0, strpos($mime, '/')), $mimes); + } + + /** + * Return true if voume is readable. + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + public function isReadable() { + $stat = $this->stat($this->root); + return $stat['read']; + } + + /** + * Return true if copy from this volume allowed + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + public function copyFromAllowed() { + return !!$this->options['copyFrom']; + } + + /** + * Return file path related to root + * + * @param string $hash file hash + * @return string + * @author Dmitry (dio) Levashov + **/ + public function path($hash) { + return $this->_path($this->decode($hash)); + } + + /** + * Return file real path if file exists + * + * @param string $hash file hash + * @return string + * @author Dmitry (dio) Levashov + **/ + public function realpath($hash) { + $path = $this->decode($hash); + return $this->stat($path) ? $path : false; + } + + /** + * Return list of moved/overwrited files + * + * @return array + * @author Dmitry (dio) Levashov + **/ + public function removed() { + return $this->removed; + } + + /** + * Clean removed files list + * + * @return void + * @author Dmitry (dio) Levashov + **/ + public function resetRemoved() { + $this->removed = array(); + } + + /** + * Return file/dir hash or first founded child hash with required attr == $val + * + * @param string $hash file hash + * @param string $attr attribute name + * @param bool $val attribute value + * @return string|false + * @author Dmitry (dio) Levashov + **/ + public function closest($hash, $attr, $val) { + return ($path = $this->closestByAttr($this->decode($hash), $attr, $val)) ? $this->encode($path) : false; + } + + /** + * Return file info or false on error + * + * @param string $hash file hash + * @param bool $realpath add realpath field to file info + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function file($hash) { + $path = $this->decode($hash); + + return ($file = $this->stat($path)) ? $file : $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + + if (($file = $this->stat($path)) != false) { + if ($realpath) { + $file['realpath'] = $path; + } + return $file; + } + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + + /** + * Return folder info + * + * @param string $hash folder hash + * @param bool $hidden return hidden file info + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function dir($hash, $resolveLink=false) { + if (($dir = $this->file($hash)) == false) { + return $this->setError(elFinder::ERROR_DIR_NOT_FOUND); + } + + if ($resolveLink && !empty($dir['thash'])) { + $dir = $this->file($dir['thash']); + } + + return $dir && $dir['mime'] == 'directory' && empty($dir['hidden']) + ? $dir + : $this->setError(elFinder::ERROR_NOT_DIR); + } + + /** + * Return directory content or false on error + * + * @param string $hash file hash + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function scandir($hash) { + if (($dir = $this->dir($hash)) == false) { + return false; + } + + return $dir['read'] + ? $this->getScandir($this->decode($hash)) + : $this->setError(elFinder::ERROR_PERM_DENIED); + } + + /** + * Return dir files names list + * + * @param string $hash file hash + * @return array + * @author Dmitry (dio) Levashov + **/ + public function ls($hash) { + if (($dir = $this->dir($hash)) == false || !$dir['read']) { + return false; + } + + $list = array(); + $path = $this->decode($hash); + + foreach ($this->getScandir($path) as $stat) { + if (empty($stat['hidden']) && $this->mimeAccepted($stat['mime'])) { + $list[] = $stat['name']; + } + } + + return $list; + } + + /** + * Return subfolders for required folder or false on error + * + * @param string $hash folder hash or empty string to get tree from root folder + * @param int $deep subdir deep + * @param string $exclude dir hash which subfolders must be exluded from result, required to not get stat twice on cwd subfolders + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function tree($hash='', $deep=0, $exclude='') { + $path = $hash ? $this->decode($hash) : $this->root; + + if (($dir = $this->stat($path)) == false || $dir['mime'] != 'directory') { + return false; + } + + $dirs = $this->gettree($path, $deep > 0 ? $deep -1 : $this->treeDeep-1, $this->decode($exclude)); + array_unshift($dirs, $dir); + return $dirs; + } + + /** + * Return part of dirs tree from required dir up to root dir + * + * @param string $hash directory hash + * @return array + * @author Dmitry (dio) Levashov + **/ + public function parents($hash) { + if (($current = $this->dir($hash)) == false) { + return false; + } + + $path = $this->decode($hash); + $tree = array(); + + while ($path && $path != $this->root) { + $path = $this->_dirname($path); + $stat = $this->stat($path); + if (!empty($stat['hidden']) || !$stat['read']) { + return false; + } + + array_unshift($tree, $stat); + if ($path != $this->root) { + foreach ($this->gettree($path, 0) as $dir) { + if (!in_array($dir, $tree)) { + $tree[] = $dir; + } + } + } + } + + return $tree ? $tree : array($current); + } + + /** + * Create thumbnail for required file and return its name of false on failed + * + * @return string|false + * @author Dmitry (dio) Levashov + **/ + public function tmb($hash) { + $path = $this->decode($hash); + $stat = $this->stat($path); + + if (isset($stat['tmb'])) { + return $stat['tmb'] == "1" ? $this->createTmb($path, $stat) : $stat['tmb']; + } + return false; + } + + /** + * Return file size / total directory size + * + * @param string file hash + * @return int + * @author Dmitry (dio) Levashov + **/ + public function size($hash) { + return $this->countSize($this->decode($hash)); + } + + /** + * Open file for reading and return file pointer + * + * @param string file hash + * @return Resource + * @author Dmitry (dio) Levashov + **/ + public function open($hash) { + if (($file = $this->file($hash)) == false + || $file['mime'] == 'directory') { + return false; + } + + return $this->_fopen($this->decode($hash), 'rb'); + } + + /** + * Close file pointer + * + * @param Resource $fp file pointer + * @param string $hash file hash + * @return void + * @author Dmitry (dio) Levashov + **/ + public function close($fp, $hash) { + $this->_fclose($fp, $this->decode($hash)); + } + + /** + * Create directory and return dir info + * + * @param string $dst destination directory + * @param string $name directory name + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function mkdir($dst, $name) { + if ($this->commandDisabled('mkdir')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (!$this->nameAccepted($name)) { + return $this->setError(elFinder::ERROR_INVALID_NAME); + } + + if (($dir = $this->dir($dst)) == false) { + return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dst); + } + + if (!$dir['write']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + $path = $this->decode($dst); + $dst = $this->_joinPath($path, $name); + $stat = $this->stat($dst); + if (!empty($stat)) { + return $this->setError(elFinder::ERROR_EXISTS, $name); + } + $this->clearcache(); + return ($path = $this->_mkdir($path, $name)) ? $this->stat($path) : false; + } + + /** + * Create empty file and return its info + * + * @param string $dst destination directory + * @param string $name file name + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function mkfile($dst, $name) { + if ($this->commandDisabled('mkfile')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (!$this->nameAccepted($name)) { + return $this->setError(elFinder::ERROR_INVALID_NAME); + } + + if (($dir = $this->dir($dst)) == false) { + return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dst); + } + + if (!$dir['write']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + $path = $this->decode($dst); + + if ($this->stat($this->_joinPath($path, $name))) { + return $this->setError(elFinder::ERROR_EXISTS, $name); + } + $this->clearcache(); + return ($path = $this->_mkfile($path, $name)) ? $this->stat($path) : false; + } + + /** + * Rename file and return file info + * + * @param string $hash file hash + * @param string $name new file name + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function rename($hash, $name) { + if ($this->commandDisabled('rename')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (!$this->nameAccepted($name)) { + return $this->setError(elFinder::ERROR_INVALID_NAME, $name); + } + + if (!($file = $this->file($hash))) { + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + + if ($name == $file['name']) { + return $file; + } + + if (!empty($file['locked'])) { + return $this->setError(elFinder::ERROR_LOCKED, $file['name']); + } + + $path = $this->decode($hash); + $dir = $this->_dirname($path); + $stat = $this->stat($this->_joinPath($dir, $name)); + if ($stat) { + return $this->setError(elFinder::ERROR_EXISTS, $name); + } + + if (!$this->_move($path, $dir, $name)) { + return false; + } + + if (!empty($stat['tmb']) && $stat['tmb'] != "1") { + $this->rmTmb($stat['tmb']); + } + + $path = $this->_joinPath($dir, $name); + + $this->clearcache(); + return $this->stat($path); + } + + /** + * Create file copy with suffix "copy number" and return its info + * + * @param string $hash file hash + * @param string $suffix suffix to add to file name + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function duplicate($hash, $suffix='copy') { + if ($this->commandDisabled('duplicate')) { + return $this->setError(elFinder::ERROR_COPY, '#'.$hash, elFinder::ERROR_PERM_DENIED); + } + + if (($file = $this->file($hash)) == false) { + return $this->setError(elFinder::ERROR_COPY, elFinder::ERROR_FILE_NOT_FOUND); + } + + $path = $this->decode($hash); + $dir = $this->_dirname($path); + + return ($path = $this->copy($path, $dir, $this->uniqueName($dir, $this->_basename($path), ' '.$suffix.' '))) == false + ? false + : $this->stat($path); + } + + /** + * Save uploaded file. + * On success return array with new file stat and with removed file hash (if existed file was replaced) + * + * @param Resource $fp file pointer + * @param string $dst destination folder hash + * @param string $src file name + * @param string $tmpname file tmp name - required to detect mime type + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function upload($fp, $dst, $name, $tmpname) { + if ($this->commandDisabled('upload')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (($dir = $this->dir($dst)) == false) { + return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dst); + } + + if (!$dir['write']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (!$this->nameAccepted($name)) { + return $this->setError(elFinder::ERROR_INVALID_NAME); + } + + $mime = $this->mimetype($this->mimeDetect == 'internal' ? $name : $tmpname); + if ($mime == 'unknown' && $this->mimeDetect == 'internal') { + $mime = elFinderVolumeDriver::mimetypeInternalDetect($name); + } + + // logic based on http://httpd.apache.org/docs/2.2/mod/mod_authz_host.html#order + $allow = $this->mimeAccepted($mime, $this->uploadAllow, null); + $deny = $this->mimeAccepted($mime, $this->uploadDeny, null); + $upload = true; // default to allow + if (strtolower($this->uploadOrder[0]) == 'allow') { // array('allow', 'deny'), default is to 'deny' + $upload = false; // default is deny + if (!$deny && ($allow === true)) { // match only allow + $upload = true; + }// else (both match | no match | match only deny) { deny } + } else { // array('deny', 'allow'), default is to 'allow' - this is the default rule + $upload = true; // default is allow + if (($deny === true) && !$allow) { // match only deny + $upload = false; + } // else (both match | no match | match only allow) { allow } + } + if (!$upload) { + return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME); + } + + if ($this->uploadMaxSize > 0 && filesize($tmpname) > $this->uploadMaxSize) { + return $this->setError(elFinder::ERROR_UPLOAD_FILE_SIZE); + } + + $dstpath = $this->decode($dst); + $test = $this->_joinPath($dstpath, $name); + + $file = $this->stat($test); + $this->clearcache(); + + if ($file) { // file exists + if ($this->options['uploadOverwrite']) { + if (!$file['write']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } elseif ($file['mime'] == 'directory') { + return $this->setError(elFinder::ERROR_NOT_REPLACE, $name); + } + $this->remove($file); + } else { + $name = $this->uniqueName($dstpath, $name, '-', false); + } + } + + $w = $h = 0; + if (strpos($mime, 'image') === 0 && ($s = getimagesize($tmpname))) { + $w = $s[0]; + $h = $s[1]; + } + // $this->clearcache(); + if (($path = $this->_save($fp, $dstpath, $name, $mime, $w, $h)) == false) { + return false; + } + + + + return $this->stat($path); + } + + /** + * Paste files + * + * @param Object $volume source volume + * @param string $source file hash + * @param string $dst destination dir hash + * @param bool $rmSrc remove source after copy? + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function paste($volume, $src, $dst, $rmSrc = false) { + $err = $rmSrc ? elFinder::ERROR_MOVE : elFinder::ERROR_COPY; + + if ($this->commandDisabled('paste')) { + return $this->setError($err, '#'.$src, elFinder::ERROR_PERM_DENIED); + } + + if (($file = $volume->file($src, $rmSrc)) == false) { + return $this->setError($err, '#'.$src, elFinder::ERROR_FILE_NOT_FOUND); + } + + $name = $file['name']; + $errpath = $volume->path($src); + + if (($dir = $this->dir($dst)) == false) { + return $this->setError($err, $errpath, elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dst); + } + + if (!$dir['write'] || !$file['read']) { + return $this->setError($err, $errpath, elFinder::ERROR_PERM_DENIED); + } + + $destination = $this->decode($dst); + + if (($test = $volume->closest($src, $rmSrc ? 'locked' : 'read', $rmSrc))) { + return $rmSrc + ? $this->setError($err, $errpath, elFinder::ERROR_LOCKED, $volume->path($test)) + : $this->setError($err, $errpath, elFinder::ERROR_PERM_DENIED); + } + + $test = $this->_joinPath($destination, $name); + $stat = $this->stat($test); + $this->clearcache(); + if ($stat) { + if ($this->options['copyOverwrite']) { + // do not replace file with dir or dir with file + if (!$this->isSameType($file['mime'], $stat['mime'])) { + return $this->setError(elFinder::ERROR_NOT_REPLACE, $this->_path($test)); + } + // existed file is not writable + if (!$stat['write']) { + return $this->setError($err, $errpath, elFinder::ERROR_PERM_DENIED); + } + // existed file locked or has locked child + if (($locked = $this->closestByAttr($test, 'locked', true))) { + return $this->setError(elFinder::ERROR_LOCKED, $this->_path($locked)); + } + // remove existed file + if (!$this->remove($test)) { + return $this->setError(elFinder::ERROR_REPLACE, $this->_path($test)); + } + } else { + $name = $this->uniqueName($destination, $name, ' ', false); + } + } + + // copy/move inside current volume + if ($volume == $this) { + $source = $this->decode($src); + // do not copy into itself + if ($this->_inpath($destination, $source)) { + return $this->setError(elFinder::ERROR_COPY_INTO_ITSELF, $path); + } + $method = $rmSrc ? 'move' : 'copy'; + + return ($path = $this->$method($source, $destination, $name)) ? $this->stat($path) : false; + } + + + // copy/move from another volume + if (!$this->options['copyTo'] || !$volume->copyFromAllowed()) { + return $this->setError(elFinder::ERROR_COPY, $errpath, elFinder::ERROR_PERM_DENIED); + } + + if (($path = $this->copyFrom($volume, $src, $destination, $name)) == false) { + return false; + } + + if ($rmSrc) { + if ($volume->rm($src)) { + $this->removed[] = $file; + } else { + return $this->setError(elFinder::ERROR_MOVE, $errpath, elFinder::ERROR_RM_SRC); + } + } + return $this->stat($path); + } + + /** + * Return file contents + * + * @param string $hash file hash + * @return string|false + * @author Dmitry (dio) Levashov + **/ + public function getContents($hash) { + $file = $this->file($hash); + + if (!$file) { + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + + if ($file['mime'] == 'directory') { + return $this->setError(elFinder::ERROR_NOT_FILE); + } + + if (!$file['read']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + return $this->_getContents($this->decode($hash)); + } + + /** + * Put content in text file and return file info. + * + * @param string $hash file hash + * @param string $content new file content + * @return array + * @author Dmitry (dio) Levashov + **/ + public function putContents($hash, $content) { + if ($this->commandDisabled('edit')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + $path = $this->decode($hash); + + if (!($file = $this->file($hash))) { + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + + if (!$file['write']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + $this->clearcache(); + return $this->_filePutContents($path, $content) ? $this->stat($path) : false; + } + + /** + * Extract files from archive + * + * @param string $hash archive hash + * @return array|bool + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + public function extract($hash) { + if ($this->commandDisabled('extract')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (($file = $this->file($hash)) == false) { + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + + $archiver = isset($this->archivers['extract'][$file['mime']]) + ? $this->archivers['extract'][$file['mime']] + : false; + + if (!$archiver) { + return $this->setError(elFinder::ERROR_NOT_ARCHIVE); + } + + $path = $this->decode($hash); + $parent = $this->stat($this->_dirname($path)); + + if (!$file['read'] || !$parent['write']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + $this->clearcache(); + return ($path = $this->_extract($path, $archiver)) ? $this->stat($path) : false; + } + + /** + * Add files to archive + * + * @return void + **/ + public function archive($hashes, $mime) { + if ($this->commandDisabled('archive')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + $archiver = isset($this->archivers['create'][$mime]) + ? $this->archivers['create'][$mime] + : false; + + if (!$archiver) { + return $this->setError(elFinder::ERROR_ARCHIVE_TYPE); + } + + $files = array(); + + foreach ($hashes as $hash) { + if (($file = $this->file($hash)) == false) { + return $this->error(elFinder::ERROR_FILE_NOT_FOUND, '#'+$hash); + } + if (!$file['read']) { + return $this->error(elFinder::ERROR_PERM_DENIED); + } + $path = $this->decode($hash); + if (!isset($dir)) { + $dir = $this->_dirname($path); + $stat = $this->stat($dir); + if (!$stat['write']) { + return $this->error(elFinder::ERROR_PERM_DENIED); + } + } + + $files[] = $this->_basename($path); + } + + $name = (count($files) == 1 ? $files[0] : 'Archive').'.'.$archiver['ext']; + $name = $this->uniqueName($dir, $name, ''); + $this->clearcache(); + return ($path = $this->_archive($dir, $files, $name, $archiver)) ? $this->stat($path) : false; + } + + /** + * Resize image + * + * @param string $hash image file + * @param int $width new width + * @param int $height new height + * @param int $x X start poistion for crop + * @param int $y Y start poistion for crop + * @param string $mode action how to mainpulate image + * @return array|false + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + * @author nao-pon + * @author Troex Nevelin + **/ + public function resize($hash, $width, $height, $x, $y, $mode = 'resize', $bg = '', $degree = 0) { + if ($this->commandDisabled('resize')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (($file = $this->file($hash)) == false) { + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + + if (!$file['write'] || !$file['read']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + $path = $this->decode($hash); + + if (!$this->canResize($path, $file)) { + return $this->setError(elFinder::ERROR_UNSUPPORT_TYPE); + } + + switch($mode) { + + case 'propresize': + $result = $this->imgResize($path, $width, $height, true, true); + break; + + case 'crop': + $result = $this->imgCrop($path, $width, $height, $x, $y); + break; + + case 'fitsquare': + $result = $this->imgSquareFit($path, $width, $height, 'center', 'middle', ($bg ? $bg : $this->options['tmbBgColor'])); + break; + + case 'rotate': + $result = $this->imgRotate($path, $degree, ($bg ? $bg : $this->options['tmbBgColor'])); + break; + + default: + $result = $this->imgResize($path, $width, $height, false, true); + break; + } + + if ($result) { + if (!empty($file['tmb']) && $file['tmb'] != "1") { + $this->rmTmb($file['tmb']); + } + $this->clearcache(); + return $this->stat($path); + } + + return false; + } + + /** + * Remove file/dir + * + * @param string $hash file hash + * @return bool + * @author Dmitry (dio) Levashov + **/ + public function rm($hash) { + return $this->commandDisabled('rm') + ? array(elFinder::ERROR_ACCESS_DENIED) + : $this->remove($this->decode($hash)); + } + + /** + * Search files + * + * @param string $q search string + * @param array $mimes + * @return array + * @author Dmitry (dio) Levashov + **/ + public function search($q, $mimes) { + return $this->doSearch($this->root, $q, $mimes); + } + + /** + * Return image dimensions + * + * @param string $hash file hash + * @return array + * @author Dmitry (dio) Levashov + **/ + public function dimensions($hash) { + if (($file = $this->file($hash)) == false) { + return false; + } + + return $this->_dimensions($this->decode($hash), $file['mime']); + } + + /** + * Save error message + * + * @param array error + * @return false + * @author Dmitry(dio) Levashov + **/ + protected function setError($error) { + + $this->error = array(); + + foreach (func_get_args() as $err) { + if (is_array($err)) { + $this->error = array_merge($this->error, $err); + } else { + $this->error[] = $err; + } + } + + // $this->error = is_array($error) ? $error : func_get_args(); + return false; + } + + /*********************************************************************/ + /* FS API */ + /*********************************************************************/ + + /***************** paths *******************/ + + /** + * Encode path into hash + * + * @param string file path + * @return string + * @author Dmitry (dio) Levashov + * @author Troex Nevelin + **/ + protected function encode($path) { + if ($path !== '') { + + // cut ROOT from $path for security reason, even if hacker decodes the path he will not know the root + $p = $this->_relpath($path); + // if reqesting root dir $path will be empty, then assign '/' as we cannot leave it blank for crypt + if ($p === '') { + $p = DIRECTORY_SEPARATOR; + } + + // TODO crypt path and return hash + $hash = $this->crypt($p); + // hash is used as id in HTML that means it must contain vaild chars + // make base64 html safe and append prefix in begining + $hash = strtr(base64_encode($hash), '+/=', '-_.'); + // remove dots '.' at the end, before it was '=' in base64 + $hash = rtrim($hash, '.'); + // append volume id to make hash unique + return $this->id.$hash; + } + } + + /** + * Decode path from hash + * + * @param string file hash + * @return string + * @author Dmitry (dio) Levashov + * @author Troex Nevelin + **/ + protected function decode($hash) { + if (strpos($hash, $this->id) === 0) { + // cut volume id after it was prepended in encode + $h = substr($hash, strlen($this->id)); + // replace HTML safe base64 to normal + $h = base64_decode(strtr($h, '-_.', '+/=')); + // TODO uncrypt hash and return path + $path = $this->uncrypt($h); + // append ROOT to path after it was cut in encode + return $this->_abspath($path);//$this->root.($path == DIRECTORY_SEPARATOR ? '' : DIRECTORY_SEPARATOR.$path); + } + } + + /** + * Return crypted path + * Not implemented + * + * @param string path + * @return mixed + * @author Dmitry (dio) Levashov + **/ + protected function crypt($path) { + return $path; + } + + /** + * Return uncrypted path + * Not implemented + * + * @param mixed hash + * @return mixed + * @author Dmitry (dio) Levashov + **/ + protected function uncrypt($hash) { + return $hash; + } + + /** + * Validate file name based on $this->options['acceptedName'] regexp + * + * @param string $name file name + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function nameAccepted($name) { + if ($this->nameValidator) { + if (function_exists($this->nameValidator)) { + $f = $this->nameValidator; + return $f($name); + } + return preg_match($this->nameValidator, $name); + } + return true; + } + + /** + * Return new unique name based on file name and suffix + * + * @param string $path file path + * @param string $suffix suffix append to name + * @return string + * @author Dmitry (dio) Levashov + **/ + public function uniqueName($dir, $name, $suffix = ' copy', $checkNum=true) { + $ext = ''; + + if (preg_match('/\.((tar\.(gz|bz|bz2|z|lzo))|cpio\.gz|ps\.gz|xcf\.(gz|bz2)|[a-z0-9]{1,4})$/i', $name, $m)) { + $ext = '.'.$m[1]; + $name = substr($name, 0, strlen($name)-strlen($m[0])); + } + + if ($checkNum && preg_match('/('.$suffix.')(\d*)$/i', $name, $m)) { + $i = (int)$m[2]; + $name = substr($name, 0, strlen($name)-strlen($m[2])); + } else { + $i = 1; + $name .= $suffix; + } + $max = $i+100000; + + while ($i <= $max) { + $n = $name.($i > 0 ? $i : '').$ext; + + if (!$this->stat($this->_joinPath($dir, $n))) { + $this->clearcache(); + return $n; + } + $i++; + } + return $name.md5($dir).$ext; + } + + /*********************** file stat *********************/ + + /** + * Check file attribute + * + * @param string $path file path + * @param string $name attribute name (read|write|locked|hidden) + * @param bool $val attribute value returned by file system + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function attr($path, $name, $val=false) { + if (!isset($this->defaults[$name])) { + return false; + } + + + $perm = null; + + if ($this->access) { + if (is_array($this->access)) { + $obj = $this->access[0]; + $method = $this->access[1]; + $perm = $obj->{$method}($name, $path, $this->options['accessControlData'], $this); + } else { + $func = $this->access; + $perm = $func($name, $path, $this->options['accessControlData'], $this); + } + + if ($perm !== null) { + return !!$perm; + } + } + + for ($i = 0, $c = count($this->attributes); $i < $c; $i++) { + $attrs = $this->attributes[$i]; + $p = $this->separator.$this->_relpath($path); + if (isset($attrs[$name]) && isset($attrs['pattern']) && preg_match($attrs['pattern'], $p)) { + $perm = $attrs[$name]; + } + } + + return $perm === null ? $this->defaults[$name] : !!$perm; + } + + /** + * Return fileinfo + * + * @param string $path file cache + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function stat($path) { + return isset($this->cache[$path]) + ? $this->cache[$path] + : $this->updateCache($path, $this->_stat($path)); + } + + /** + * Put file stat in cache and return it + * + * @param string $path file path + * @param array $stat file stat + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function updateCache($path, $stat) { + if (empty($stat) || !is_array($stat)) { + return $this->cache[$path] = array(); + } + + $stat['hash'] = $this->encode($path); + + $root = $path == $this->root; + + if ($root) { + $stat['volumeid'] = $this->id; + if ($this->rootName) { + $stat['name'] = $this->rootName; + } + } else { + if (empty($stat['name'])) { + $stat['name'] = $this->_basename($path); + } + if (empty($stat['phash'])) { + $stat['phash'] = $this->encode($this->_dirname($path)); + } + } + + // fix name if required + if ($this->options['utf8fix'] && $this->options['utf8patterns'] && $this->options['utf8replace']) { + $stat['name'] = json_decode(str_replace($this->options['utf8patterns'], $this->options['utf8replace'], json_encode($stat['name']))); + } + + + if (empty($stat['mime'])) { + $stat['mime'] = $this->mimetype($stat['name']); + } + + // @todo move dateformat to client + $stat['date'] = isset($stat['ts']) + ? $this->formatDate($stat['ts']) + : 'unknown'; + + if (!isset($stat['size'])) { + $stat['size'] = 'unknown'; + } + + $stat['read'] = intval($this->attr($path, 'read', isset($stat['read']) ? !!$stat['read'] : false)); + $stat['write'] = intval($this->attr($path, 'write', isset($stat['write']) ? !!$stat['write'] : false)); + if ($root) { + $stat['locked'] = 1; + } elseif ($this->attr($path, 'locked', !empty($stat['locked']))) { + $stat['locked'] = 1; + } else { + unset($stat['locked']); + } + + if ($root) { + unset($stat['hidden']); + } elseif ($this->attr($path, 'hidden', !empty($stat['hidden'])) + || !$this->mimeAccepted($stat['mime'])) { + $stat['hidden'] = $root ? 0 : 1; + } else { + unset($stat['hidden']); + } + + if ($stat['read'] && empty($stat['hidden'])) { + + if ($stat['mime'] == 'directory') { + // for dir - check for subdirs + + if ($this->options['checkSubfolders']) { + if (isset($stat['dirs'])) { + if ($stat['dirs']) { + $stat['dirs'] = 1; + } else { + unset($stat['dirs']); + } + } elseif (!empty($stat['alias']) && !empty($stat['target'])) { + $stat['dirs'] = isset($this->cache[$stat['target']]) + ? intval(isset($this->cache[$stat['target']]['dirs'])) + : $this->_subdirs($stat['target']); + + } elseif ($this->_subdirs($path)) { + $stat['dirs'] = 1; + } + } else { + $stat['dirs'] = 1; + } + } else { + // for files - check for thumbnails + $p = isset($stat['target']) ? $stat['target'] : $path; + if ($this->tmbURL && !isset($stat['tmb']) && $this->canCreateTmb($p, $stat)) { + $tmb = $this->gettmb($p, $stat); + $stat['tmb'] = $tmb ? $tmb : 1; + } + + } + } + + if (!empty($stat['alias']) && !empty($stat['target'])) { + $stat['thash'] = $this->encode($stat['target']); + unset($stat['target']); + } + + return $this->cache[$path] = $stat; + } + + /** + * Get stat for folder content and put in cache + * + * @param string $path + * @return void + * @author Dmitry (dio) Levashov + **/ + protected function cacheDir($path) { + $this->dirsCache[$path] = array(); + + foreach ($this->_scandir($path) as $p) { + if (($stat = $this->stat($p)) && empty($stat['hidden'])) { + $this->dirsCache[$path][] = $p; + } + } + } + + /** + * Clean cache + * + * @return void + * @author Dmitry (dio) Levashov + **/ + protected function clearcache() { + $this->cache = $this->dirsCache = array(); + } + + /** + * Return file mimetype + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function mimetype($path) { + $type = ''; + + if ($this->mimeDetect == 'finfo') { + $type = @finfo_file($this->finfo, $path); + } elseif ($type == 'mime_content_type') { + $type = mime_content_type($path); + } else { + $type = elFinderVolumeDriver::mimetypeInternalDetect($path); + } + + $type = explode(';', $type); + $type = trim($type[0]); + + if ($type == 'application/x-empty') { + // finfo return this mime for empty files + $type = 'text/plain'; + } elseif ($type == 'application/x-zip') { + // http://elrte.org/redmine/issues/163 + $type = 'application/zip'; + } + + return $type == 'unknown' && $this->mimeDetect != 'internal' + ? elFinderVolumeDriver::mimetypeInternalDetect($path) + : $type; + + } + + /** + * Detect file mimetype using "internal" method + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + static protected function mimetypeInternalDetect($path) { + $pinfo = pathinfo($path); + $ext = isset($pinfo['extension']) ? strtolower($pinfo['extension']) : ''; + return isset(elFinderVolumeDriver::$mimetypes[$ext]) ? elFinderVolumeDriver::$mimetypes[$ext] : 'unknown'; + + } + + /** + * Return file/total directory size + * + * @param string $path file path + * @return int + * @author Dmitry (dio) Levashov + **/ + protected function countSize($path) { + $stat = $this->stat($path); + + if (empty($stat) || !$stat['read'] || !empty($stat['hidden'])) { + return 'unknown'; + } + + if ($stat['mime'] != 'directory') { + return $stat['size']; + } + + $subdirs = $this->options['checkSubfolders']; + $this->options['checkSubfolders'] = true; + $result = 0; + foreach ($this->getScandir($path) as $stat) { + $size = $stat['mime'] == 'directory' && $stat['read'] + ? $this->countSize($this->_joinPath($path, $stat['name'])) + : $stat['size']; + if ($size > 0) { + $result += $size; + } + } + $this->options['checkSubfolders'] = $subdirs; + return $result; + } + + /** + * Return true if all mimes is directory or files + * + * @param string $mime1 mimetype + * @param string $mime2 mimetype + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function isSameType($mime1, $mime2) { + return ($mime1 == 'directory' && $mime1 == $mime2) || ($mime1 != 'directory' && $mime2 != 'directory'); + } + + /** + * If file has required attr == $val - return file path, + * If dir has child with has required attr == $val - return child path + * + * @param string $path file path + * @param string $attr attribute name + * @param bool $val attribute value + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function closestByAttr($path, $attr, $val) { + $stat = $this->stat($path); + + if (empty($stat)) { + return false; + } + + $v = isset($stat[$attr]) ? $stat[$attr] : false; + + if ($v == $val) { + return $path; + } + + return $stat['mime'] == 'directory' + ? $this->childsByAttr($path, $attr, $val) + : false; + } + + /** + * Return first found children with required attr == $val + * + * @param string $path file path + * @param string $attr attribute name + * @param bool $val attribute value + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function childsByAttr($path, $attr, $val) { + foreach ($this->_scandir($path) as $p) { + if (($_p = $this->closestByAttr($p, $attr, $val)) != false) { + return $_p; + } + } + return false; + } + + /***************** get content *******************/ + + /** + * Return required dir's files info. + * If onlyMimes is set - return only dirs and files of required mimes + * + * @param string $path dir path + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function getScandir($path) { + $files = array(); + + !isset($this->dirsCache[$path]) && $this->cacheDir($path); + + foreach ($this->dirsCache[$path] as $p) { + if (($stat = $this->stat($p)) && empty($stat['hidden'])) { + $files[] = $stat; + } + } + + return $files; + } + + + /** + * Return subdirs tree + * + * @param string $path parent dir path + * @param int $deep tree deep + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function gettree($path, $deep, $exclude='') { + $dirs = array(); + + !isset($this->dirsCache[$path]) && $this->cacheDir($path); + + foreach ($this->dirsCache[$path] as $p) { + $stat = $this->stat($p); + + if ($stat && empty($stat['hidden']) && $path != $exclude && $stat['mime'] == 'directory') { + $dirs[] = $stat; + if ($deep > 0 && !empty($stat['dirs'])) { + $dirs = array_merge($dirs, $this->gettree($p, $deep-1)); + } + } + } + + return $dirs; + } + + /** + * Recursive files search + * + * @param string $path dir path + * @param string $q search string + * @param array $mimes + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function doSearch($path, $q, $mimes) { + $result = array(); + + foreach($this->_scandir($path) as $p) { + $stat = $this->stat($p); + + if (!$stat) { // invalid links + continue; + } + + if (!empty($stat['hidden']) || !$this->mimeAccepted($stat['mime'])) { + continue; + } + + $name = $stat['name']; + + if ($this->stripos($name, $q) !== false) { + $stat['path'] = $this->_path($p); + if ($this->URL && !isset($stat['url'])) { + $stat['url'] = $this->URL . str_replace($this->separator, '/', substr($p, strlen($this->root) + 1)); + } + + $result[] = $stat; + } + if ($stat['mime'] == 'directory' && $stat['read'] && !isset($stat['alias'])) { + $result = array_merge($result, $this->doSearch($p, $q, $mimes)); + } + } + + return $result; + } + + /********************** manuipulations ******************/ + + /** + * Copy file/recursive copy dir only in current volume. + * Return new file path or false. + * + * @param string $src source path + * @param string $dst destination dir path + * @param string $name new file name (optionaly) + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function copy($src, $dst, $name) { + $srcStat = $this->stat($src); + $this->clearcache(); + + if (!empty($srcStat['thash'])) { + $target = $this->decode($srcStat['thash']); + $stat = $this->stat($target); + $this->clearcache(); + return $stat && $this->_symlink($target, $dst, $name) + ? $this->_joinPath($dst, $name) + : $this->setError(elFinder::ERROR_COPY, $this->_path($src)); + } + + if ($srcStat['mime'] == 'directory') { + $test = $this->stat($this->_joinPath($dst, $name)); + + if (($test && $test['mime'] != 'directory') || !$this->_mkdir($dst, $name)) { + return $this->setError(elFinder::ERROR_COPY, $this->_path($src)); + } + + $dst = $this->_joinPath($dst, $name); + + foreach ($this->getScandir($src) as $stat) { + if (empty($stat['hidden'])) { + $name = $stat['name']; + if (!$this->copy($this->_joinPath($src, $name), $dst, $name)) { + return false; + } + } + } + $this->clearcache(); + return $dst; + } + + return $this->_copy($src, $dst, $name) + ? $this->_joinPath($dst, $name) + : $this->setError(elFinder::ERROR_COPY, $this->_path($src)); + } + + /** + * Move file + * Return new file path or false. + * + * @param string $src source path + * @param string $dst destination dir path + * @param string $name new file name + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function move($src, $dst, $name) { + $stat = $this->stat($src); + $stat['realpath'] = $src; + $this->clearcache(); + + if ($this->_move($src, $dst, $name)) { + $this->removed[] = $stat; + return $this->_joinPath($dst, $name); + } + + return $this->setError(elFinder::ERROR_MOVE, $this->_path($src)); + } + + /** + * Copy file from another volume. + * Return new file path or false. + * + * @param Object $volume source volume + * @param string $src source file hash + * @param string $destination destination dir path + * @param string $name file name + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function copyFrom($volume, $src, $destination, $name) { + + if (($source = $volume->file($src)) == false) { + return $this->setError(elFinder::ERROR_COPY, '#'.$src, $volume->error()); + } + + $errpath = $volume->path($src); + + if (!$this->nameAccepted($source['name'])) { + return $this->setError(elFinder::ERROR_COPY, $errpath, elFinder::ERROR_INVALID_NAME); + } + + if (!$source['read']) { + return $this->setError(elFinder::ERROR_COPY, $errpath, elFinder::ERROR_PERM_DENIED); + } + + if ($source['mime'] == 'directory') { + $stat = $this->stat($this->_joinPath($destination, $name)); + $this->clearcache(); + if ((!$stat || $stat['mime'] != 'directory') && !$this->_mkdir($destination, $name)) { + return $this->setError(elFinder::ERROR_COPY, $errpath); + } + + $path = $this->_joinPath($destination, $name); + + foreach ($volume->scandir($src) as $entr) { + if (!$this->copyFrom($volume, $entr['hash'], $path, $entr['name'])) { + return false; + } + } + + } else { + $mime = $source['mime']; + $w = $h = 0; + if (strpos($mime, 'image') === 0 && ($dim = $volume->dimensions($src))) { + $s = explode('x', $dim); + $w = $s[0]; + $h = $s[1]; + } + + if (($fp = $volume->open($src)) == false + || ($path = $this->_save($fp, $destination, $name, $mime, $w, $h)) == false) { + $fp && $volume->close($fp, $src); + return $this->setError(elFinder::ERROR_COPY, $errpath); + } + $volume->close($fp, $src); + } + + return $path; + } + + /** + * Remove file/ recursive remove dir + * + * @param string $path file path + * @param bool $force try to remove even if file locked + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function remove($path, $force = false) { + $stat = $this->stat($path); + $stat['realpath'] = $path; + if (!empty($stat['tmb']) && $stat['tmb'] != "1") { + $this->rmTmb($stat['tmb']); + } + $this->clearcache(); + + if (empty($stat)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND); + } + + if (!$force && !empty($stat['locked'])) { + return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path)); + } + + if ($stat['mime'] == 'directory') { + foreach ($this->_scandir($path) as $p) { + $name = $this->_basename($p); + if ($name != '.' && $name != '..' && !$this->remove($p)) { + return false; + } + } + if (!$this->_rmdir($path)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path)); + } + + } else { + if (!$this->_unlink($path)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path)); + } + } + + $this->removed[] = $stat; + return true; + } + + + /************************* thumbnails **************************/ + + /** + * Return thumbnail file name for required file + * + * @param array $stat file stat + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function tmbname($stat) { + return $stat['hash'].$stat['ts'].'.png'; + } + + /** + * Return thumnbnail name if exists + * + * @param string $path file path + * @param array $stat file stat + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function gettmb($path, $stat) { + if ($this->tmbURL && $this->tmbPath) { + // file itself thumnbnail + if (strpos($path, $this->tmbPath) === 0) { + return basename($path); + } + + $name = $this->tmbname($stat); + if (file_exists($this->tmbPath.DIRECTORY_SEPARATOR.$name)) { + return $name; + } + } + return false; + } + + /** + * Return true if thumnbnail for required file can be created + * + * @param string $path thumnbnail path + * @param array $stat file stat + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function canCreateTmb($path, $stat) { + return $this->tmbPathWritable + && strpos($path, $this->tmbPath) === false // do not create thumnbnail for thumnbnail + && $this->imgLib + && strpos($stat['mime'], 'image') === 0 + && ($this->imgLib == 'gd' ? $stat['mime'] == 'image/jpeg' || $stat['mime'] == 'image/png' || $stat['mime'] == 'image/gif' : true); + } + + /** + * Return true if required file can be resized. + * By default - the same as canCreateTmb + * + * @param string $path thumnbnail path + * @param array $stat file stat + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function canResize($path, $stat) { + return $this->canCreateTmb($path, $stat); + } + + /** + * Create thumnbnail and return it's URL on success + * + * @param string $path file path + * @param string $mime file mime type + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function createTmb($path, $stat) { + if (!$stat || !$this->canCreateTmb($path, $stat)) { + return false; + } + + $name = $this->tmbname($stat); + $tmb = $this->tmbPath.DIRECTORY_SEPARATOR.$name; + + // copy image into tmbPath so some drivers does not store files on local fs + if (($src = $this->_fopen($path, 'rb')) == false) { + return false; + } + + if (($trg = fopen($tmb, 'wb')) == false) { + $this->_fclose($src, $path); + return false; + } + + while (!feof($src)) { + fwrite($trg, fread($src, 8192)); + } + + $this->_fclose($src, $path); + fclose($trg); + + $result = false; + + $tmbSize = $this->tmbSize; + + if (($s = getimagesize($tmb)) == false) { + return false; + } + + /* If image smaller or equal thumbnail size - just fitting to thumbnail square */ + if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) { + $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png' ); + + } else { + + if ($this->options['tmbCrop']) { + + /* Resize and crop if image bigger than thumbnail */ + if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize) ) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png'); + } + + if (($s = getimagesize($tmb)) != false) { + $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize)/2) : 0; + $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize)/2) : 0; + $result = $this->imgCrop($tmb, $tmbSize, $tmbSize, $x, $y, 'png'); + } + + } else { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, $this->imgLib, 'png'); + $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png' ); + } + + } + if (!$result) { + unlink($tmb); + return false; + } + + return $name; + } + + /** + * Resize image + * + * @param string $path image file + * @param int $width new width + * @param int $height new height + * @param bool $keepProportions crop image + * @param bool $resizeByBiggerSide resize image based on bigger side if true + * @param string $destformat image destination format + * @return string|false + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + **/ + protected function imgResize($path, $width, $height, $keepProportions = false, $resizeByBiggerSide = true, $destformat = null) { + if (($s = @getimagesize($path)) == false) { + return false; + } + + $result = false; + + list($size_w, $size_h) = array($width, $height); + + if ($keepProportions == true) { + + list($orig_w, $orig_h, $new_w, $new_h) = array($s[0], $s[1], $width, $height); + + /* Calculating image scale width and height */ + $xscale = $orig_w / $new_w; + $yscale = $orig_h / $new_h; + + /* Resizing by biggest side */ + + if ($resizeByBiggerSide) { + + if ($orig_w > $orig_h) { + $size_h = $orig_h * $width / $orig_w; + $size_w = $width; + } else { + $size_w = $orig_w * $height / $orig_h; + $size_h = $height; + } + + } else { + if ($orig_w > $orig_h) { + $size_w = $orig_w * $height / $orig_h; + $size_h = $height; + } else { + $size_h = $orig_h * $width / $orig_w; + $size_w = $width; + } + } + } + + switch ($this->imgLib) { + case 'imagick': + + try { + $img = new imagick($path); + } catch (Exception $e) { + + return false; + } + + $img->resizeImage($size_w, $size_h, Imagick::FILTER_LANCZOS, true); + + $result = $img->writeImage($path); + + return $result ? $path : false; + + break; + + case 'gd': + if ($s['mime'] == 'image/jpeg') { + $img = imagecreatefromjpeg($path); + } elseif ($s['mime'] == 'image/png') { + $img = imagecreatefrompng($path); + } elseif ($s['mime'] == 'image/gif') { + $img = imagecreatefromgif($path); + } elseif ($s['mime'] == 'image/xbm') { + $img = imagecreatefromxbm($path); + } + + if ($img && false != ($tmp = imagecreatetruecolor($size_w, $size_h))) { + if (!imagecopyresampled($tmp, $img, 0, 0, 0, 0, $size_w, $size_h, $s[0], $s[1])) { + return false; + } + + if ($destformat == 'jpg' || ($destformat == null && $s['mime'] == 'image/jpeg')) { + $result = imagejpeg($tmp, $path, 100); + } else if ($destformat == 'gif' || ($destformat == null && $s['mime'] == 'image/gif')) { + $result = imagegif($tmp, $path, 7); + } else { + $result = imagepng($tmp, $path, 7); + } + + imagedestroy($img); + imagedestroy($tmp); + + return $result ? $path : false; + + } + break; + } + + return false; + } + + /** + * Crop image + * + * @param string $path image file + * @param int $width crop width + * @param int $height crop height + * @param bool $x crop left offset + * @param bool $y crop top offset + * @param string $destformat image destination format + * @return string|false + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + **/ + protected function imgCrop($path, $width, $height, $x, $y, $destformat = null) { + if (($s = @getimagesize($path)) == false) { + return false; + } + + $result = false; + + switch ($this->imgLib) { + case 'imagick': + + try { + $img = new imagick($path); + } catch (Exception $e) { + + return false; + } + + $img->cropImage($width, $height, $x, $y); + + $result = $img->writeImage($path); + + return $result ? $path : false; + + break; + + case 'gd': + if ($s['mime'] == 'image/jpeg') { + $img = imagecreatefromjpeg($path); + } elseif ($s['mime'] == 'image/png') { + $img = imagecreatefrompng($path); + } elseif ($s['mime'] == 'image/gif') { + $img = imagecreatefromgif($path); + } elseif ($s['mime'] == 'image/xbm') { + $img = imagecreatefromxbm($path); + } + + if ($img && false != ($tmp = imagecreatetruecolor($width, $height))) { + + if (!imagecopy($tmp, $img, 0, 0, $x, $y, $width, $height)) { + return false; + } + + if ($destformat == 'jpg' || ($destformat == null && $s['mime'] == 'image/jpeg')) { + $result = imagejpeg($tmp, $path, 100); + } else if ($destformat == 'gif' || ($destformat == null && $s['mime'] == 'image/gif')) { + $result = imagegif($tmp, $path, 7); + } else { + $result = imagepng($tmp, $path, 7); + } + + imagedestroy($img); + imagedestroy($tmp); + + return $result ? $path : false; + + } + break; + } + + return false; + } + + /** + * Put image to square + * + * @param string $path image file + * @param int $width square width + * @param int $height square height + * @param int $align reserved + * @param int $valign reserved + * @param string $bgcolor square background color in #rrggbb format + * @param string $destformat image destination format + * @return string|false + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + **/ + protected function imgSquareFit($path, $width, $height, $align = 'center', $valign = 'middle', $bgcolor = '#0000ff', $destformat = null) { + if (($s = @getimagesize($path)) == false) { + return false; + } + + $result = false; + + /* Coordinates for image over square aligning */ + $y = ceil(abs($height - $s[1]) / 2); + $x = ceil(abs($width - $s[0]) / 2); + + switch ($this->imgLib) { + case 'imagick': + try { + $img = new imagick($path); + } catch (Exception $e) { + return false; + } + + $img1 = new Imagick(); + $img1->newImage($width, $height, new ImagickPixel($bgcolor)); + $img1->setImageColorspace($img->getImageColorspace()); + $img1->setImageFormat($destformat != null ? $destformat : $img->getFormat()); + $img1->compositeImage( $img, imagick::COMPOSITE_OVER, $x, $y ); + $result = $img1->writeImage($path); + return $result ? $path : false; + + break; + + case 'gd': + if ($s['mime'] == 'image/jpeg') { + $img = imagecreatefromjpeg($path); + } elseif ($s['mime'] == 'image/png') { + $img = imagecreatefrompng($path); + } elseif ($s['mime'] == 'image/gif') { + $img = imagecreatefromgif($path); + } elseif ($s['mime'] == 'image/xbm') { + $img = imagecreatefromxbm($path); + } + + if ($img && false != ($tmp = imagecreatetruecolor($width, $height))) { + + if ($bgcolor == 'transparent') { + list($r, $g, $b) = array(0, 0, 255); + } else { + list($r, $g, $b) = sscanf($bgcolor, "#%02x%02x%02x"); + } + + $bgcolor1 = imagecolorallocate($tmp, $r, $g, $b); + + if ($bgcolor == 'transparent') { + $bgcolor1 = imagecolortransparent($tmp, $bgcolor1); + } + + imagefill($tmp, 0, 0, $bgcolor1); + + if (!imagecopy($tmp, $img, $x, $y, 0, 0, $s[0], $s[1])) { + return false; + } + + if ($destformat == 'jpg' || ($destformat == null && $s['mime'] == 'image/jpeg')) { + $result = imagejpeg($tmp, $path, 100); + } else if ($destformat == 'gif' || ($destformat == null && $s['mime'] == 'image/gif')) { + $result = imagegif($tmp, $path, 7); + } else { + $result = imagepng($tmp, $path, 7); + } + + imagedestroy($img); + imagedestroy($tmp); + + return $result ? $path : false; + } + break; + } + + return false; + } + + /** + * Rotate image + * + * @param string $path image file + * @param int $degree rotete degrees + * @param string $bgcolor square background color in #rrggbb format + * @param string $destformat image destination format + * @return string|false + * @author nao-pon + * @author Troex Nevelin + **/ + protected function imgRotate($path, $degree, $bgcolor = '#ffffff', $destformat = null) { + if (($s = @getimagesize($path)) == false) { + return false; + } + + $result = false; + + switch ($this->imgLib) { + case 'imagick': + try { + $img = new imagick($path); + } catch (Exception $e) { + return false; + } + + $img->rotateImage(new ImagickPixel($bgcolor), $degree); + $result = $img->writeImage($path); + return $result ? $path : false; + + break; + + case 'gd': + if ($s['mime'] == 'image/jpeg') { + $img = imagecreatefromjpeg($path); + } elseif ($s['mime'] == 'image/png') { + $img = imagecreatefrompng($path); + } elseif ($s['mime'] == 'image/gif') { + $img = imagecreatefromgif($path); + } elseif ($s['mime'] == 'image/xbm') { + $img = imagecreatefromxbm($path); + } + + $degree = 360 - $degree; + list($r, $g, $b) = sscanf($bgcolor, "#%02x%02x%02x"); + $bgcolor = imagecolorallocate($img, $r, $g, $b); + $tmp = imageRotate($img, $degree, (int)$bgcolor); + + if ($destformat == 'jpg' || ($destformat == null && $s['mime'] == 'image/jpeg')) { + $result = imagejpeg($tmp, $path, 100); + } else if ($destformat == 'gif' || ($destformat == null && $s['mime'] == 'image/gif')) { + $result = imagegif($tmp, $path, 7); + } else { + $result = imagepng($tmp, $path, 7); + } + + imageDestroy($img); + imageDestroy($tmp); + + return $result ? $path : false; + + break; + } + + return false; + } + + /** + * Execute shell command + * + * @param string $command command line + * @param array $output stdout strings + * @param array $return_var process exit code + * @param array $error_output stderr strings + * @return int exit code + * @author Alexey Sukhotin + **/ + protected function procExec($command , array &$output = null, &$return_var = -1, array &$error_output = null) { + + $descriptorspec = array( + 0 => array("pipe", "r"), // stdin + 1 => array("pipe", "w"), // stdout + 2 => array("pipe", "w") // stderr + ); + + $process = proc_open($command, $descriptorspec, $pipes, null, null); + + if (is_resource($process)) { + + fclose($pipes[0]); + + $tmpout = ''; + $tmperr = ''; + + $output = stream_get_contents($pipes[1]); + $error_output = stream_get_contents($pipes[2]); + + fclose($pipes[1]); + fclose($pipes[2]); + $return_var = proc_close($process); + + + } + + return $return_var; + + } + + /** + * Remove thumbnail + * + * @param string $path file path + * @return void + * @author Dmitry (dio) Levashov + **/ + protected function rmTmb($tmb) { + $tmb = $this->tmbPath.DIRECTORY_SEPARATOR.$tmb; + file_exists($tmb) && @unlink($tmb); + clearstatcache(); + } + + /*********************** misc *************************/ + + /** + * Return smart formatted date + * + * @param int $ts file timestamp + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function formatDate($ts) { + if ($ts > $this->today) { + return 'Today '.date($this->options['timeFormat'], $ts); + } + + if ($ts > $this->yesterday) { + return 'Yesterday '.date($this->options['timeFormat'], $ts); + } + + return date($this->options['dateFormat'], $ts); + } + + /** + * Find position of first occurrence of string in a string with multibyte support + * + * @param string $haystack The string being checked. + * @param string $needle The string to find in haystack. + * @param int $offset The search offset. If it is not specified, 0 is used. + * @return int|bool + * @author Alexey Sukhotin + **/ + protected function stripos($haystack , $needle , $offset = 0) { + if (function_exists('mb_stripos')) { + return mb_stripos($haystack , $needle , $offset); + } else if (function_exists('mb_strtolower') && function_exists('mb_strpos')) { + return mb_strpos(mb_strtolower($haystack), mb_strtolower($needle), $offset); + } + return stripos($haystack , $needle , $offset); + } + + /**==================================* abstract methods *====================================**/ + + /*********************** paths/urls *************************/ + + /** + * Return parent directory path + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _dirname($path); + + /** + * Return file name + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _basename($path); + + /** + * Join dir name and file name and return full path. + * Some drivers (db) use int as path - so we give to concat path to driver itself + * + * @param string $dir dir path + * @param string $name file name + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _joinPath($dir, $name); + + /** + * Return normalized path + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _normpath($path); + + /** + * Return file path related to root dir + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _relpath($path); + + /** + * Convert path related to root dir into real path + * + * @param string $path rel file path + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _abspath($path); + + /** + * Return fake path started from root dir. + * Required to show path on client side. + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _path($path); + + /** + * Return true if $path is children of $parent + * + * @param string $path path to check + * @param string $parent parent path + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _inpath($path, $parent); + + /** + * Return stat for given path. + * Stat contains following fields: + * - (int) size file size in b. required + * - (int) ts file modification time in unix time. required + * - (string) mime mimetype. required for folders, others - optionally + * - (bool) read read permissions. required + * - (bool) write write permissions. required + * - (bool) locked is object locked. optionally + * - (bool) hidden is object hidden. optionally + * - (string) alias for symlinks - link target path relative to root path. optionally + * - (string) target for symlinks - link target path. optionally + * + * If file does not exists - returns empty array or false. + * + * @param string $path file path + * @return array|false + * @author Dmitry (dio) Levashov + **/ + abstract protected function _stat($path); + + + /***************** file stat ********************/ + + + /** + * Return true if path is dir and has at least one childs directory + * + * @param string $path dir path + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _subdirs($path); + + /** + * Return object width and height + * Ususaly used for images, but can be realize for video etc... + * + * @param string $path file path + * @param string $mime file mime type + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _dimensions($path, $mime); + + /******************** file/dir content *********************/ + + /** + * Return files list in directory + * + * @param string $path dir path + * @return array + * @author Dmitry (dio) Levashov + **/ + abstract protected function _scandir($path); + + /** + * Open file and return file pointer + * + * @param string $path file path + * @param bool $write open file for writing + * @return resource|false + * @author Dmitry (dio) Levashov + **/ + abstract protected function _fopen($path, $mode="rb"); + + /** + * Close opened file + * + * @param resource $fp file pointer + * @param string $path file path + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _fclose($fp, $path=''); + + /******************** file/dir manipulations *************************/ + + /** + * Create dir and return created dir path or false on failed + * + * @param string $path parent dir path + * @param string $name new directory name + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _mkdir($path, $name); + + /** + * Create file and return it's path or false on failed + * + * @param string $path parent dir path + * @param string $name new file name + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _mkfile($path, $name); + + /** + * Create symlink + * + * @param string $source file to link to + * @param string $targetDir folder to create link in + * @param string $name symlink name + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _symlink($source, $targetDir, $name); + + /** + * Copy file into another file (only inside one volume) + * + * @param string $source source file path + * @param string $target target dir path + * @param string $name file name + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _copy($source, $targetDir, $name); + + /** + * Move file into another parent dir. + * Return new file path or false. + * + * @param string $source source file path + * @param string $target target dir path + * @param string $name file name + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _move($source, $targetDir, $name); + + /** + * Remove file + * + * @param string $path file path + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _unlink($path); + + /** + * Remove dir + * + * @param string $path dir path + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _rmdir($path); + + /** + * Create new file and write into it from file pointer. + * Return new file path or false on error. + * + * @param resource $fp file pointer + * @param string $dir target dir path + * @param string $name file name + * @return bool|string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _save($fp, $dir, $name, $mime, $w, $h); + + /** + * Get file contents + * + * @param string $path file path + * @return string|false + * @author Dmitry (dio) Levashov + **/ + abstract protected function _getContents($path); + + /** + * Write a string to a file + * + * @param string $path file path + * @param string $content new file content + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _filePutContents($path, $content); + + /** + * Extract files from archive + * + * @param string $path file path + * @param array $arc archiver options + * @return bool + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + abstract protected function _extract($path, $arc); + + /** + * Create archive and return its path + * + * @param string $dir target dir + * @param array $files files names list + * @param string $name archive name + * @param array $arc archiver options + * @return string|bool + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + abstract protected function _archive($dir, $files, $name, $arc); + + /** + * Detect available archivers + * + * @return void + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + abstract protected function _checkArchivers(); + +} // END class diff --git a/administrator/components/com_k2/lib/elfinder/elFinderVolumeLocalFileSystem.class.php b/administrator/components/com_k2/lib/elfinder/elFinderVolumeLocalFileSystem.class.php new file mode 100644 index 0000000..3048bbd --- /dev/null +++ b/administrator/components/com_k2/lib/elfinder/elFinderVolumeLocalFileSystem.class.php @@ -0,0 +1,845 @@ +options['alias'] = ''; // alias to replace root dir name + $this->options['dirMode'] = 0755; // new dirs mode + $this->options['fileMode'] = 0644; // new files mode + $this->options['quarantine'] = '.quarantine'; // quarantine folder name - required to check archive (must be hidden) + $this->options['maxArcFilesSize'] = 0; // max allowed archive files size (0 - no limit) + } + + /*********************************************************************/ + /* INIT AND CONFIGURE */ + /*********************************************************************/ + + /** + * Configure after successfull mount. + * + * @return void + * @author Dmitry (dio) Levashov + **/ + protected function configure() { + $this->aroot = realpath($this->root); + $root = $this->stat($this->root); + + if ($this->options['quarantine']) { + $this->attributes[] = array( + 'pattern' => '~^'.preg_quote(DIRECTORY_SEPARATOR.$this->options['quarantine']).'$~', + 'read' => false, + 'write' => false, + 'locked' => true, + 'hidden' => true + ); + } + + // chek thumbnails path + if ($this->options['tmbPath']) { + $this->options['tmbPath'] = strpos($this->options['tmbPath'], DIRECTORY_SEPARATOR) === false + // tmb path set as dirname under root dir + ? $this->root.DIRECTORY_SEPARATOR.$this->options['tmbPath'] + // tmb path as full path + : $this->_normpath($this->options['tmbPath']); + } + + parent::configure(); + + // if no thumbnails url - try detect it + if ($root['read'] && !$this->tmbURL && $this->URL) { + if (strpos($this->tmbPath, $this->root) === 0) { + $this->tmbURL = $this->URL.str_replace(DIRECTORY_SEPARATOR, '/', substr($this->tmbPath, strlen($this->root)+1)); + if (preg_match("|[^/?&=]$|", $this->tmbURL)) { + $this->tmbURL .= '/'; + } + } + } + + // check quarantine dir + if (!empty($this->options['quarantine'])) { + $this->quarantine = $this->root.DIRECTORY_SEPARATOR.$this->options['quarantine']; + if ((!is_dir($this->quarantine) && !$this->_mkdir($this->root, $this->options['quarantine'])) || !is_writable($this->quarantine)) { + $this->archivers['extract'] = array(); + $this->disabled[] = 'extract'; + } + } else { + $this->archivers['extract'] = array(); + $this->disabled[] = 'extract'; + } + + } + + /*********************************************************************/ + /* FS API */ + /*********************************************************************/ + + /*********************** paths/urls *************************/ + + /** + * Return parent directory path + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _dirname($path) { + return dirname($path); + } + + /** + * Return file name + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _basename($path) { + return basename($path); + } + + /** + * Join dir name and file name and retur full path + * + * @param string $dir + * @param string $name + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _joinPath($dir, $name) { + return $dir.DIRECTORY_SEPARATOR.$name; + } + + /** + * Return normalized path, this works the same as os.path.normpath() in Python + * + * @param string $path path + * @return string + * @author Troex Nevelin + **/ + protected function _normpath($path) { + if (empty($path)) { + return '.'; + } + + if (strpos($path, '/') === 0) { + $initial_slashes = true; + } else { + $initial_slashes = false; + } + + if (($initial_slashes) + && (strpos($path, '//') === 0) + && (strpos($path, '///') === false)) { + $initial_slashes = 2; + } + + $initial_slashes = (int) $initial_slashes; + + $comps = explode('/', $path); + $new_comps = array(); + foreach ($comps as $comp) { + if (in_array($comp, array('', '.'))) { + continue; + } + + if (($comp != '..') + || (!$initial_slashes && !$new_comps) + || ($new_comps && (end($new_comps) == '..'))) { + array_push($new_comps, $comp); + } elseif ($new_comps) { + array_pop($new_comps); + } + } + $comps = $new_comps; + $path = implode('/', $comps); + if ($initial_slashes) { + $path = str_repeat('/', $initial_slashes) . $path; + } + + return $path ? $path : '.'; + } + + /** + * Return file path related to root dir + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _relpath($path) { + return $path == $this->root ? '' : substr($path, strlen($this->root)+1); + } + + /** + * Convert path related to root dir into real path + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _abspath($path) { + return $path == DIRECTORY_SEPARATOR ? $this->root : $this->root.DIRECTORY_SEPARATOR.$path; + } + + /** + * Return fake path started from root dir + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _path($path) { + return $this->rootName.($path == $this->root ? '' : $this->separator.$this->_relpath($path)); + } + + /** + * Return true if $path is children of $parent + * + * @param string $path path to check + * @param string $parent parent path + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _inpath($path, $parent) { + return $path == $parent || strpos($path, $parent.DIRECTORY_SEPARATOR) === 0; + } + + + + /***************** file stat ********************/ + + /** + * Return stat for given path. + * Stat contains following fields: + * - (int) size file size in b. required + * - (int) ts file modification time in unix time. required + * - (string) mime mimetype. required for folders, others - optionally + * - (bool) read read permissions. required + * - (bool) write write permissions. required + * - (bool) locked is object locked. optionally + * - (bool) hidden is object hidden. optionally + * - (string) alias for symlinks - link target path relative to root path. optionally + * - (string) target for symlinks - link target path. optionally + * + * If file does not exists - returns empty array or false. + * + * @param string $path file path + * @return array|false + * @author Dmitry (dio) Levashov + **/ + protected function _stat($path) { + $stat = array(); + + if (!file_exists($path)) { + return $stat; + } + + if ($path != $this->root && is_link($path)) { + if (($target = $this->readlink($path)) == false + || $target == $path) { + $stat['mime'] = 'symlink-broken'; + $stat['read'] = false; + $stat['write'] = false; + $stat['size'] = 0; + return $stat; + } + $stat['alias'] = $this->_path($target); + $stat['target'] = $target; + $path = $target; + $lstat = lstat($path); + $size = $lstat['size']; + } else { + $size = @filesize($path); + } + + $dir = is_dir($path); + + $stat['mime'] = $dir ? 'directory' : $this->mimetype($path); + $stat['ts'] = filemtime($path); + $stat['read'] = is_readable($path); + $stat['write'] = is_writable($path); + if ($stat['read']) { + $stat['size'] = $dir ? 0 : $size; + } + + return $stat; + } + + + /** + * Return true if path is dir and has at least one childs directory + * + * @param string $path dir path + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _subdirs($path) { + + if (($dir = dir($path))) { + $dir = dir($path); + while (($entry = $dir->read()) !== false) { + $p = $dir->path.DIRECTORY_SEPARATOR.$entry; + if ($entry != '.' && $entry != '..' && is_dir($p) && !$this->attr($p, 'hidden')) { + $dir->close(); + return true; + } + } + $dir->close(); + } + return false; + } + + /** + * Return object width and height + * Ususaly used for images, but can be realize for video etc... + * + * @param string $path file path + * @param string $mime file mime type + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _dimensions($path, $mime) { + clearstatcache(); + return strpos($mime, 'image') === 0 && ($s = @getimagesize($path)) !== false + ? $s[0].'x'.$s[1] + : false; + } + /******************** file/dir content *********************/ + + /** + * Return symlink target file + * + * @param string $path link path + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function readlink($path) { + if (!($target = @readlink($path))) { + return false; + } + + if (substr($target, 0, 1) != DIRECTORY_SEPARATOR) { + $target = dirname($path).DIRECTORY_SEPARATOR.$target; + } + + $atarget = realpath($target); + + if (!$atarget) { + return false; + } + + $root = $this->root; + $aroot = $this->aroot; + + if ($this->_inpath($atarget, $this->aroot)) { + return $this->_normpath($this->root.DIRECTORY_SEPARATOR.substr($atarget, strlen($this->aroot)+1)); + } + + return false; + } + + /** + * Return files list in directory. + * + * @param string $path dir path + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function _scandir($path) { + $files = array(); + + foreach (scandir($path) as $name) { + if ($name != '.' && $name != '..') { + $files[] = $path.DIRECTORY_SEPARATOR.$name; + } + } + return $files; + } + + /** + * Open file and return file pointer + * + * @param string $path file path + * @param bool $write open file for writing + * @return resource|false + * @author Dmitry (dio) Levashov + **/ + protected function _fopen($path, $mode='rb') { + return @fopen($path, 'r'); + } + + /** + * Close opened file + * + * @param resource $fp file pointer + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _fclose($fp, $path='') { + return @fclose($fp); + } + + /******************** file/dir manipulations *************************/ + + /** + * Create dir and return created dir path or false on failed + * + * @param string $path parent dir path + * @param string $name new directory name + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkdir($path, $name) { + $path = $path.DIRECTORY_SEPARATOR.$name; + + if (@mkdir($path)) { + @chmod($path, $this->options['dirMode']); + return $path; + } + + return false; + } + + /** + * Create file and return it's path or false on failed + * + * @param string $path parent dir path + * @param string $name new file name + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkfile($path, $name) { + $path = $path.DIRECTORY_SEPARATOR.$name; + + if (($fp = @fopen($path, 'w'))) { + @fclose($fp); + @chmod($path, $this->options['fileMode']); + return $path; + } + return false; + } + + /** + * Create symlink + * + * @param string $source file to link to + * @param string $targetDir folder to create link in + * @param string $name symlink name + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _symlink($source, $targetDir, $name) { + return @symlink($source, $targetDir.DIRECTORY_SEPARATOR.$name); + } + + /** + * Copy file into another file + * + * @param string $source source file path + * @param string $targetDir target directory path + * @param string $name new file name + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _copy($source, $targetDir, $name) { + return copy($source, $targetDir.DIRECTORY_SEPARATOR.$name); + } + + /** + * Move file into another parent dir. + * Return new file path or false. + * + * @param string $source source file path + * @param string $target target dir path + * @param string $name file name + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _move($source, $targetDir, $name) { + $target = $targetDir.DIRECTORY_SEPARATOR.$name; + return @rename($source, $target) ? $target : false; + } + + /** + * Remove file + * + * @param string $path file path + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _unlink($path) { + return @unlink($path); + } + + /** + * Remove dir + * + * @param string $path dir path + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _rmdir($path) { + return @rmdir($path); + } + + /** + * Create new file and write into it from file pointer. + * Return new file path or false on error. + * + * @param resource $fp file pointer + * @param string $dir target dir path + * @param string $name file name + * @return bool|string + * @author Dmitry (dio) Levashov + **/ + protected function _save($fp, $dir, $name, $mime, $w, $h) { + $path = $dir.DIRECTORY_SEPARATOR.$name; + + if (!($target = @fopen($path, 'wb'))) { + return false; + } + + while (!feof($fp)) { + fwrite($target, fread($fp, 8192)); + } + fclose($target); + @chmod($path, $this->options['fileMode']); + clearstatcache(); + return $path; + } + + /** + * Get file contents + * + * @param string $path file path + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function _getContents($path) { + return file_get_contents($path); + } + + /** + * Write a string to a file + * + * @param string $path file path + * @param string $content new file content + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _filePutContents($path, $content) { + if (@file_put_contents($path, $content, LOCK_EX) !== false) { + clearstatcache(); + return true; + } + return false; + } + + /** + * Detect available archivers + * + * @return void + **/ + protected function _checkArchivers() { + if (!function_exists('exec')) { + $this->options['archivers'] = $this->options['archive'] = array(); + return; + } + $arcs = array( + 'create' => array(), + 'extract' => array() + ); + + //exec('tar --version', $o, $ctar); + $this->procExec('tar --version', $o, $ctar); + + if ($ctar == 0) { + $arcs['create']['application/x-tar'] = array('cmd' => 'tar', 'argc' => '-cf', 'ext' => 'tar'); + $arcs['extract']['application/x-tar'] = array('cmd' => 'tar', 'argc' => '-xf', 'ext' => 'tar'); + //$test = exec('gzip --version', $o, $c); + unset($o); + $test = $this->procExec('gzip --version', $o, $c); + + if ($c == 0) { + $arcs['create']['application/x-gzip'] = array('cmd' => 'tar', 'argc' => '-czf', 'ext' => 'tgz'); + $arcs['extract']['application/x-gzip'] = array('cmd' => 'tar', 'argc' => '-xzf', 'ext' => 'tgz'); + } + unset($o); + //$test = exec('bzip2 --version', $o, $c); + $test = $this->procExec('bzip2 --version', $o, $c); + if ($c == 0) { + $arcs['create']['application/x-bzip2'] = array('cmd' => 'tar', 'argc' => '-cjf', 'ext' => 'tbz'); + $arcs['extract']['application/x-bzip2'] = array('cmd' => 'tar', 'argc' => '-xjf', 'ext' => 'tbz'); + } + } + unset($o); + //exec('zip --version', $o, $c); + $this->procExec('zip -v', $o, $c); + if ($c == 0) { + $arcs['create']['application/zip'] = array('cmd' => 'zip', 'argc' => '-r9', 'ext' => 'zip'); + } + unset($o); + $this->procExec('unzip --help', $o, $c); + if ($c == 0) { + $arcs['extract']['application/zip'] = array('cmd' => 'unzip', 'argc' => '', 'ext' => 'zip'); + } + unset($o); + //exec('rar --version', $o, $c); + $this->procExec('rar --version', $o, $c); + if ($c == 0 || $c == 7) { + $arcs['create']['application/x-rar'] = array('cmd' => 'rar', 'argc' => 'a -inul', 'ext' => 'rar'); + $arcs['extract']['application/x-rar'] = array('cmd' => 'rar', 'argc' => 'x -y', 'ext' => 'rar'); + } else { + unset($o); + //$test = exec('unrar', $o, $c); + $test = $this->procExec('unrar', $o, $c); + if ($c==0 || $c == 7) { + $arcs['extract']['application/x-rar'] = array('cmd' => 'unrar', 'argc' => 'x -y', 'ext' => 'rar'); + } + } + unset($o); + //exec('7za --help', $o, $c); + $this->procExec('7za --help', $o, $c); + if ($c == 0) { + $arcs['create']['application/x-7z-compressed'] = array('cmd' => '7za', 'argc' => 'a', 'ext' => '7z'); + $arcs['extract']['application/x-7z-compressed'] = array('cmd' => '7za', 'argc' => 'e -y', 'ext' => '7z'); + + if (empty($arcs['create']['application/x-gzip'])) { + $arcs['create']['application/x-gzip'] = array('cmd' => '7za', 'argc' => 'a -tgzip', 'ext' => 'tar.gz'); + } + if (empty($arcs['extract']['application/x-gzip'])) { + $arcs['extract']['application/x-gzip'] = array('cmd' => '7za', 'argc' => 'e -tgzip -y', 'ext' => 'tar.gz'); + } + if (empty($arcs['create']['application/x-bzip2'])) { + $arcs['create']['application/x-bzip2'] = array('cmd' => '7za', 'argc' => 'a -tbzip2', 'ext' => 'tar.bz'); + } + if (empty($arcs['extract']['application/x-bzip2'])) { + $arcs['extract']['application/x-bzip2'] = array('cmd' => '7za', 'argc' => 'a -tbzip2 -y', 'ext' => 'tar.bz'); + } + if (empty($arcs['create']['application/zip'])) { + $arcs['create']['application/zip'] = array('cmd' => '7za', 'argc' => 'a -tzip -l', 'ext' => 'zip'); + } + if (empty($arcs['extract']['application/zip'])) { + $arcs['extract']['application/zip'] = array('cmd' => '7za', 'argc' => 'e -tzip -y', 'ext' => 'zip'); + } + if (empty($arcs['create']['application/x-tar'])) { + $arcs['create']['application/x-tar'] = array('cmd' => '7za', 'argc' => 'a -ttar -l', 'ext' => 'tar'); + } + if (empty($arcs['extract']['application/x-tar'])) { + $arcs['extract']['application/x-tar'] = array('cmd' => '7za', 'argc' => 'e -ttar -y', 'ext' => 'tar'); + } + } + + $this->archivers = $arcs; + } + + /** + * Unpack archive + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * @return void + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + **/ + protected function _unpack($path, $arc) { + $cwd = getcwd(); + $dir = $this->_dirname($path); + chdir($dir); + $cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg($this->_basename($path)); + $this->procExec($cmd, $o, $c); + chdir($cwd); + } + + /** + * Recursive symlinks search + * + * @param string $path file/dir path + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _findSymlinks($path) { + if (is_link($path)) { + return true; + } + + if (is_dir($path)) { + foreach (scandir($path) as $name) { + if ($name != '.' && $name != '..') { + $p = $path.DIRECTORY_SEPARATOR.$name; + if (is_link($p)) { + return true; + } + if (is_dir($p) && $this->_findSymlinks($p)) { + return true; + } elseif (is_file($p)) { + $this->archiveSize += filesize($p); + } + } + } + } else { + $this->archiveSize += filesize($path); + } + + return false; + } + + /** + * Extract files from archive + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * @return true + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function _extract($path, $arc) { + + if ($this->quarantine) { + $dir = $this->quarantine.DIRECTORY_SEPARATOR.str_replace(' ', '_', microtime()).basename($path); + $archive = $dir.DIRECTORY_SEPARATOR.basename($path); + + if (!@mkdir($dir)) { + return false; + } + + chmod($dir, 0755); + + // copy in quarantine + if (!copy($path, $archive)) { + return false; + } + + // extract in quarantine + $this->_unpack($archive, $arc); + @unlink($archive); + + // get files list + $ls = array(); + foreach (scandir($dir) as $i => $name) { + if ($name != '.' && $name != '..') { + $ls[] = $name; + } + } + + // no files - extract error ? + if (empty($ls)) { + return false; + } + + $this->archiveSize = 0; + + // find symlinks + $symlinks = $this->_findSymlinks($dir); + // remove arc copy + $this->remove($dir); + + if ($symlinks) { + return $this->setError(elFinder::ERROR_ARC_SYMLINKS); + } + + // check max files size + if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $this->archiveSize) { + return $this->setError(elFinder::ERROR_ARC_MAXSIZE); + } + + + + // archive contains one item - extract in archive dir + if (count($ls) == 1) { + $this->_unpack($path, $arc); + $result = dirname($path).DIRECTORY_SEPARATOR.$ls[0]; + + + } else { + // for several files - create new directory + // create unique name for directory + $name = basename($path); + if (preg_match('/\.((tar\.(gz|bz|bz2|z|lzo))|cpio\.gz|ps\.gz|xcf\.(gz|bz2)|[a-z0-9]{1,4})$/i', $name, $m)) { + $name = substr($name, 0, strlen($name)-strlen($m[0])); + } + $test = dirname($path).DIRECTORY_SEPARATOR.$name; + if (file_exists($test) || is_link($test)) { + $name = $this->uniqueName(dirname($path), $name, '-', false); + } + + $result = dirname($path).DIRECTORY_SEPARATOR.$name; + $archive = $result.DIRECTORY_SEPARATOR.basename($path); + + if (!$this->_mkdir(dirname($path), $name) || !copy($path, $archive)) { + return false; + } + + $this->_unpack($archive, $arc); + @unlink($archive); + } + + return file_exists($result) ? $result : false; + } + } + + /** + * Create archive and return its path + * + * @param string $dir target dir + * @param array $files files names list + * @param string $name archive name + * @param array $arc archiver options + * @return string|bool + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function _archive($dir, $files, $name, $arc) { + $cwd = getcwd(); + chdir($dir); + + $files = array_map('escapeshellarg', $files); + + $cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg($name).' '.implode(' ', $files); + $this->procExec($cmd, $o, $c); + chdir($cwd); + + $path = $dir.DIRECTORY_SEPARATOR.$name; + return file_exists($path) ? $path : false; + } + +} // END class diff --git a/administrator/components/com_k2/lib/elfinder/mime.types b/administrator/components/com_k2/lib/elfinder/mime.types new file mode 100644 index 0000000..94b99b7 --- /dev/null +++ b/administrator/components/com_k2/lib/elfinder/mime.types @@ -0,0 +1,512 @@ +# This file controls what Internet media types are sent to the client for +# given file extension(s). Sending the correct media type to the client +# is important so they know how to handle the content of the file. +# For more information about Internet media types, please read +# RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type +# registry is at . + +# MIME type Extension +application/andrew-inset ez +application/chemtool cht +application/dicom dcm +application/docbook+xml docbook +application/ecmascript ecma +application/flash-video flv +application/illustrator ai +application/javascript js +application/mac-binhex40 +application/mathematica nb +application/msword doc +application/octet-stream bin +application/oda oda +application/ogg ogg +application/pdf pdf +application/pgp pgp +application/pgp-encrypted +application/pgp-encrypted pgp gpg +application/pgp-keys +application/pgp-keys skr pkr +application/pgp-signature +application/pgp-signature sig +application/pkcs7-mime +application/pkcs7-signature p7s +application/postscript ps +application/rtf rtf +application/sdp sdp +application/smil smil smi sml +application/stuffit sit +application/vnd.corel-draw cdr +application/vnd.hp-hpgl hpgl +application/vnd.hp-pcl pcl +application/vnd.lotus-1-2-3 123 wk1 wk3 wk4 wks +application/vnd.mozilla.xul+xml xul +application/vnd.ms-excel xls xlc xll xlm xlw xla xlt xld +application/vnd.ms-powerpoint ppz ppt pps pot +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +application/vnd.palm pdb +application/vnd.rn-realmedia +application/vnd.rn-realmedia rm +application/vnd.rn-realmedia-secure rms +application/vnd.rn-realmedia-vbr rmvb +application/vnd.stardivision.calc sdc +application/vnd.stardivision.chart sds +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd sdp +application/vnd.stardivision.mail smd +application/vnd.stardivision.math smf +application/vnd.stardivision.writer sdw vor sgl +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +application/vnd.wordperfect wpd +application/x-abiword abw abw.CRASHED abw.gz zabw +application/x-amipro sam +application/x-anjuta-project prj +application/x-applix-spreadsheet as +application/x-applix-word aw +application/x-arc +application/x-archive a +application/x-arj arj +application/x-asax asax +application/x-ascx ascx +application/x-ashx ashx +application/x-asix asix +application/x-asmx asmx +application/x-asp asp +application/x-awk +application/x-axd axd +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-blender blender blend BLEND +application/x-bzip bz bz2 +application/x-bzip bz2 bz +application/x-bzip-compressed-tar tar.bz tar.bz2 +application/x-bzip-compressed-tar tar.bz tar.bz2 tbz tbz2 +application/x-cd-image iso +application/x-cgi cgi +application/x-chess-pgn pgn +application/x-chm chm +application/x-class-file +application/x-cmbx cmbx +application/x-compress Z +application/x-compressed-tar tar.gz tar.Z tgz taz +application/x-compressed-tar tar.gz tgz +application/x-config config +application/x-core +application/x-cpio cpio +application/x-cpio-compressed cpio.gz +application/x-csh csh +application/x-cue cue +application/x-dbase dbf +application/x-dbm +application/x-dc-rom dc +application/x-deb deb +application/x-designer ui +application/x-desktop desktop kdelnk +application/x-devhelp devhelp +application/x-dia-diagram dia +application/x-disco disco +application/x-dvi dvi +application/x-e-theme etheme +application/x-egon egon +application/x-executable exe +application/x-font-afm afm +application/x-font-bdf bdf +application/x-font-dos +application/x-font-framemaker +application/x-font-libgrx +application/x-font-linux-psf psf +application/x-font-otf +application/x-font-pcf pcf +application/x-font-pcf pcf.gz +application/x-font-speedo spd +application/x-font-sunos-news +application/x-font-tex +application/x-font-tex-tfm +application/x-font-ttf ttc TTC +application/x-font-ttf ttf +application/x-font-type1 pfa pfb gsf pcf.Z +application/x-font-vfont +application/x-frame +application/x-frontline aop +application/x-gameboy-rom gb +application/x-gdbm +application/x-gdesklets-display display +application/x-genesis-rom gen md +application/x-gettext-translation gmo +application/x-glabels glabels +application/x-glade glade +application/x-gmc-link +application/x-gnome-db-connection connection +application/x-gnome-db-database database +application/x-gnome-stones caves +application/x-gnucash gnucash gnc xac +application/x-gnumeric gnumeric +application/x-graphite gra +application/x-gtar gtar +application/x-gtktalog +application/x-gzip gz +application/x-gzpostscript ps.gz +application/x-hdf hdf +application/x-ica ica +application/x-ipod-firmware +application/x-jamin jam +application/x-jar jar +application/x-java class +application/x-java-archive jar ear war + +application/x-jbuilder-project jpr jpx +application/x-karbon karbon +application/x-kchart chrt +application/x-kformula kfo +application/x-killustrator kil +application/x-kivio flw +application/x-kontour kon +application/x-kpovmodeler kpm +application/x-kpresenter kpr kpt +application/x-krita kra +application/x-kspread ksp +application/x-kspread-crypt +application/x-ksysv-package +application/x-kugar kud +application/x-kword kwd kwt +application/x-kword-crypt +application/x-lha lha lzh +application/x-lha lzh +application/x-lhz lhz +application/x-linguist ts +application/x-lyx lyx +application/x-lzop lzo +application/x-lzop-compressed-tar tar.lzo tzo +application/x-macbinary +application/x-machine-config +application/x-magicpoint mgp +application/x-master-page master +application/x-matroska mkv +application/x-mdp mdp +application/x-mds mds +application/x-mdsx mdsx +application/x-mergeant mergeant +application/x-mif mif +application/x-mozilla-bookmarks +application/x-mps mps +application/x-ms-dos-executable exe +application/x-mswinurl +application/x-mswrite wri +application/x-msx-rom msx +application/x-n64-rom n64 +application/x-nautilus-link +application/x-nes-rom nes +application/x-netcdf cdf nc +application/x-netscape-bookmarks +application/x-object o +application/x-ole-storage +application/x-oleo oleo +application/x-palm-database +application/x-palm-database pdb prc +application/x-par2 PAR2 par2 +application/x-pef-executable +application/x-perl pl pm al perl +application/x-php php php3 php4 +application/x-pkcs12 p12 pfx +application/x-planner planner mrproject +application/x-planperfect pln +application/x-prjx prjx +application/x-profile +application/x-ptoptimizer-script pto +application/x-pw pw +application/x-python-bytecode pyc pyo +application/x-quattro-pro wb1 wb2 wb3 +application/x-quattropro wb1 wb2 wb3 +application/x-qw qif +application/x-rar rar +application/x-rar-compressed rar +application/x-rdp rdp +application/x-reject rej +application/x-remoting rem +application/x-resources resources +application/x-resourcesx resx +application/x-rpm rpm +application/x-ruby +application/x-sc +application/x-sc sc +application/x-scribus sla sla.gz scd scd.gz +application/x-shar shar +application/x-shared-library-la la +application/x-sharedlib so +application/x-shellscript sh +application/x-shockwave-flash swf +application/x-siag siag +application/x-slp +application/x-smil kino +application/x-smil smi smil +application/x-sms-rom sms gg +application/x-soap-remoting soap +application/x-streamingmedia ssm +application/x-stuffit +application/x-stuffit bin sit +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tarz tar.Z +application/x-tex-gf gf +application/x-tex-pk k +application/x-tgif obj +application/x-theme theme +application/x-toc toc +application/x-toutdoux +application/x-trash bak old sik +application/x-troff tr roff t +application/x-troff-man man +application/x-troff-man-compressed +application/x-tzo tar.lzo tzo +application/x-ustar ustar +application/x-wais-source src +application/x-web-config +application/x-wpg wpg +application/x-wsdl wsdl +application/x-x509-ca-cert der cer crt cert pem +application/x-xbel xbel +application/x-zerosize +application/x-zoo zoo +application/xhtml+xml xhtml +application/zip zip +audio/ac3 ac3 +audio/basic au snd +audio/midi mid midi +audio/mpeg mp3 +audio/prs.sid sid psid +audio/vnd.rn-realaudio ra +audio/x-aac aac +audio/x-adpcm +audio/x-aifc +audio/x-aiff aif aiff +audio/x-aiff aiff aif aifc +audio/x-aiffc +audio/x-flac flac +audio/x-m4a m4a +audio/x-mod mod ult uni XM m15 mtm 669 +audio/x-mp3-playlist +audio/x-mpeg +audio/x-mpegurl m3u +audio/x-ms-asx +audio/x-pn-realaudio ra ram rm +audio/x-pn-realaudio ram rmm +audio/x-riff +audio/x-s3m s3m +audio/x-scpls pls +audio/x-scpls pls xpl +audio/x-stm stm +audio/x-voc voc +audio/x-wav wav +audio/x-xi xi +audio/x-xm xm +image/bmp bmp +image/cgm cgm +image/dpx +image/fax-g3 g3 +image/g3fax +image/gif gif +image/ief ief +image/jpeg jpeg jpg jpe +image/jpeg2000 jp2 +image/png png +image/rle rle +image/svg+xml svg +image/tiff tif tiff +image/vnd.djvu djvu djv +image/vnd.dwg dwg +image/vnd.dxf dxf +image/x-3ds 3ds +image/x-applix-graphics ag +image/x-cmu-raster ras +image/x-compressed-xcf xcf.gz xcf.bz2 +image/x-dcraw bay BAY bmq BMQ cr2 CR2 crw CRW cs1 CS1 dc2 DC2 dcr DCR fff FFF k25 K25 kdc KDC mos MOS mrw MRW nef NEF orf ORF pef PEF raf RAF rdc RDC srf SRF x3f X3F +image/x-dib +image/x-eps eps epsi epsf +image/x-fits fits +image/x-fpx +image/x-icb icb +image/x-ico ico +image/x-iff iff +image/x-ilbm ilbm +image/x-jng jng +image/x-lwo lwo lwob +image/x-lws lws +image/x-msod msod +image/x-niff +image/x-pcx +image/x-photo-cd pcd +image/x-pict pict pict1 pict2 +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-psd psd +image/x-rgb rgb +image/x-sgi sgi +image/x-sun-raster sun +image/x-tga tga +image/x-win-bitmap cur +image/x-wmf wmf +image/x-xbitmap xbm +image/x-xcf xcf +image/x-xfig fig +image/x-xpixmap xpm +image/x-xwindowdump xwd +inode/blockdevice +inode/chardevice +inode/directory +inode/fifo +inode/mount-point +inode/socket +inode/symlink +message/delivery-status +message/disposition-notification +message/external-body +message/news +message/partial +message/rfc822 +message/x-gnu-rmail +model/vrml wrl +multipart/alternative +multipart/appledouble +multipart/digest +multipart/encrypted +multipart/mixed +multipart/related +multipart/report +multipart/signed +multipart/x-mixed-replace +text/calendar vcs ics +text/css css CSSL +text/directory vcf vct gcrd +text/enriched +text/html html htm +text/htmlh +text/mathml mml +text/plain txt asc +text/rdf rdf +text/rfc822-headers +text/richtext rtx +text/rss rss +text/sgml sgml sgm +text/spreadsheet sylk slk +text/tab-separated-values tsv +text/vnd.rn-realtext rt +text/vnd.wap.wml wml +text/x-adasrc adb ads +text/x-authors +text/x-bibtex bib +text/x-boo boo +text/x-c++hdr hh +text/x-c++src cpp cxx cc C c++ +text/x-chdr h h++ hp +text/x-comma-separated-values csv +text/x-copying +text/x-credits +text/x-csrc c +text/x-dcl dcl +text/x-dsl dsl +text/x-dsrc d +text/x-dtd dtd +text/x-emacs-lisp el +text/x-fortran f +text/x-gettext-translation po +text/x-gettext-translation-template pot +text/x-gtkrc +text/x-haskell hs +text/x-idl idl +text/x-install +text/x-java java +text/x-js js +text/x-ksysv-log +text/x-literate-haskell lhs +text/x-log log +text/x-makefile +text/x-moc moc +text/x-msil il +text/x-nemerle n +text/x-objcsrc m +text/x-pascal p pas +text/x-patch diff patch +text/x-python py +text/x-readme +text/x-rng rng +text/x-scheme scm +text/x-setext etx +text/x-speech +text/x-sql sql +text/x-suse-ymp ymp +text/x-suse-ymu ymu +text/x-tcl tcl tk +text/x-tex tex ltx sty cls +text/x-texinfo texi texinfo +text/x-texmacs tm ts +text/x-troff-me me +text/x-troff-mm mm +text/x-troff-ms ms +text/x-uil uil +text/x-uri uri url +text/x-vb vb +text/x-xds xds +text/x-xmi xmi +text/x-xsl xsl +text/x-xslfo fo xslfo +text/x-xslt xslt xsl +text/xmcd +text/xml xml +video/3gpp 3gp +video/dv dv dif +video/isivideo +video/mpeg mpeg mpg mp2 mpe vob dat +video/quicktime qt mov moov qtvr +video/vivo +video/vnd.rn-realvideo rv +video/wavelet +video/x-3gpp2 3g2 +video/x-anim anim[1-9j] +video/x-avi +video/x-flic fli flc +video/x-mng mng +video/x-ms-asf asf asx +video/x-ms-wmv wmv +video/x-msvideo avi +video/x-nsv nsv NSV +video/x-real-video +video/x-sgi-movie movie +application/x-java-jnlp-file jnlp +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +application/vnd.ms-word.document.macroEnabled.12 docm +application/vnd.ms-word.template.macroEnabled.12 dotm +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +application/vnd.ms-excel.sheet.macroEnabled.12 xlsm +application/vnd.ms-excel.template.macroEnabled.12 xltm +application/vnd.ms-excel.addin.macroEnabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroEnabled.12 xlsb +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +application/vnd.openxmlformats-officedocument.presentationml.template potx +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +application/vnd.ms-powerpoint.addin.macroEnabled.12 ppam diff --git a/administrator/components/com_k2/lib/k2parameter.php b/administrator/components/com_k2/lib/k2parameter.php new file mode 100644 index 0000000..2288b24 --- /dev/null +++ b/administrator/components/com_k2/lib/k2parameter.php @@ -0,0 +1,257 @@ +namespace = $namespace; + $this->values = new JRegistry($data); + } + + function get($path, $default = null) + { + return $this->values->get($this->namespace.$path, $default); + } + + } + +} +else +{ + + jimport('joomla.html.parameter'); + + /** + * Parameter handler + * + * @package Joomla.Framework + * @subpackage Parameter + * @since 1.5 + */ + class K2Parameter extends JParameter + { + + /** + * optional namespace + * + * @access private + * @var array + * @since 1.5 + */ + var $namespace = null; + + /** + * Constructor + * + * @access protected + * @param string The raw parms text + * @param string Path to the xml setup file + * @param string Namespace to the xml setup file + * @since 1.5 + */ + function __construct($data, $path = '', $namespace) + { + parent::__construct('_default'); + + // Set base path + $this->_elementPath[] = JPATH_COMPONENT_ADMINISTRATOR.DS.'elements'; + + if (trim($data)) + { + $this->loadINI($data); + } + + if ($path) + { + @$this->loadSetupFile($path); + } + + if ($namespace) + { + $this->namespace = $namespace; + } + + $this->_raw = $data; + + if (K2_JVERSION != '15') + { + $this->bind($data); + } + } + + /** + * Get a value + * + * @access public + * @param string The name of the param + * @param mixed The default value if not found + * @return string + * @since 1.5 + */ + function get($key, $default = '', $group = '_default') + { + if (K2_JVERSION != '15') + { + return parent::get($this->namespace.$key, $default); + } + $value = $this->getValue($group.'.'.$this->namespace.$key); + $result = (empty($value) && ($value !== 0) && ($value !== '0')) ? $default : $value; + //if($group != '_default') { echo ($group); } + return $result; + } + + /** + * Render a parameter type + * + * @param object A param tag node + * @param string The control name + * @return array Any array of the label, the form element and the tooltip + * @since 1.5 + */ + function getParam(&$node, $control_name = 'params', $group = '_default') + { + //get the type of the parameter + $type = $node->attributes('type'); + + //remove any occurance of a mos_ prefix + $type = str_replace('mos_', '', $type); + + $element = $this->loadElement($type); + + // error happened + if ($element === false) + { + $result = array(); + $result[0] = $node->attributes('name'); + $result[1] = JText::_('K2_ELEMENT_NOT_DEFINED_FOR_TYPE').' = '.$type; + $result[5] = $result[0]; + return $result; + } + + //get value + $value = $this->get($node->attributes('name'), $node->attributes('default'), $group); + + //set name + $node->_attributes['name'] = $this->namespace.$node->_attributes['name']; + + return $element->render($node, $value, $control_name); + } + + /** + * Get a registry value + * + * @access public + * @param string $regpath Registry path (e.g. joomla.content.showauthor) + * @param mixed $default Optional default value + * @return mixed Value of entry or null + * @since 1.5 + */ + function getValue($regpath, $default = null) + { + $result = $default; + + // Explode the registry path into an array + if ($nodes = explode('.', $regpath)) + { + // Get the namespace + //$namespace = array_shift($nodes); + $count = count($nodes); + if ($count < 2) + { + $namespace = $this->_defaultNameSpace; + $nodes[1] = $nodes[0]; + } + else + { + $namespace = $nodes[0]; + } + + if (isset($this->_registry[$namespace])) + { + $ns = &$this->_registry[$namespace]['data']; + $pathNodes = $count - 1; + + //for ($i = 0; $i < $pathNodes; $i ++) { + for ($i = 1; $i < $pathNodes; $i++) + { + if ((isset($ns->$nodes[$i]))) + $ns = &$ns->$nodes[$i]; + } + + if (isset($ns->$nodes[$i])) + { + $result = $ns->$nodes[$i]; + } + } + } + return $result; + } + + /** + * Render + * + * @access public + * @param string The name of the control, or the default text area if a setup file is not found + * @return string HTML + * @since 1.5 + */ + function render($name = 'params', $group = '_default') + { + if (!isset($this->_xml[$group])) + { + return false; + } + + $params = $this->getParams($name, $group); + $html = array(); + $html[] = ''; + + if ($description = $this->_xml[$group]->attributes('description')) + { + // add the params description to the display + $desc = JText::_($description); + $html[] = ''; + } + + foreach ($params as $param) + { + $html[] = ''; + + if ($param[0]) + { + $html[] = ''; + $html[] = ''; + } + else + { + $html[] = ''; + } + + $html[] = ''; + } + + if (count($params) < 1) + { + $html[] = ""; + } + + $html[] = '
    '.$desc.'
    '.$param[0].''.$param[1].''.$param[1].'
    ".(K2_JVERSION != '15') ? JText::_('JLIB_HTML_NO_PARAMETERS_FOR_THIS_ITEM') : JText::_('There are no Parameters for this item')."
    '; + + return implode("\n", $html); + } + + } + +} diff --git a/administrator/components/com_k2/lib/k2plugin.php b/administrator/components/com_k2/lib/k2plugin.php new file mode 100644 index 0000000..2959fc6 --- /dev/null +++ b/administrator/components/com_k2/lib/k2plugin.php @@ -0,0 +1,89 @@ +pluginName.'.xml' : JPATH_SITE.DS.'plugins'.DS.'k2'.DS.$this->pluginName.DS.$this->pluginName.'.xml'; + if (!empty($tab)) + { + $path = $type.'-'.$tab; + } + else + { + $path = $type; + } + if (!isset($item->plugins)) + { + $item->plugins = NULL; + } + + if (K2_JVERSION == '15') + { + + $form = new K2Parameter($item->plugins, $manifest, $this->pluginName); + $fields = $form->render('plugins', $path); + } + else + { + jimport('joomla.form.form'); + $form = JForm::getInstance('plg_k2_'.$this->pluginName.'_'.$path, $manifest, array(), true, 'fields[@group="'.$path.'"]'); + $values = array(); + if ($item->plugins) + { + foreach (json_decode($item->plugins) as $name => $value) + { + $count = 1; + $values[str_replace($this->pluginName, '', $name, $count)] = $value; + } + $form->bind($values); + } + $fields = ''; + foreach ($form->getFieldset() as $field) + { + $search = 'name="'.$field->name.'"'; + $replace = 'name="plugins['.$this->pluginName.$field->name.']"'; + $input = JString::str_ireplace($search, $replace, $field->__get('input')); + $fields .= $field->__get('label').' '.$input; + } + + // Legacy code to maintain compatibillity with existing plugins that use params instead of JForm + if (empty($fields) && K2_JVERSION == '25') + { + $form = new K2Parameter($item->plugins, $manifest, $this->pluginName); + $fields = $form->render('plugins', $path); + } + + } + if ($fields) + { + $plugin = new stdClass; + $plugin->name = $this->pluginNameHumanReadable; + $plugin->fields = $fields; + return $plugin; + } + } + +} diff --git a/administrator/components/com_k2/lib/recaptchalib.php b/administrator/components/com_k2/lib/recaptchalib.php new file mode 100644 index 0000000..51fd9e2 --- /dev/null +++ b/administrator/components/com_k2/lib/recaptchalib.php @@ -0,0 +1,288 @@ + $value ) + $req .= $key . '=' . urlencode( stripslashes($value) ) . '&'; + + // Cut the last '&' + $req=substr($req,0,strlen($req)-1); + return $req; +} + + + +/** + * Submits an HTTP POST to a reCAPTCHA server + * @param string $host + * @param string $path + * @param array $data + * @param int port + * @return array response + */ +function _recaptcha_http_post($host, $path, $data, $port = 80) { + + $req = _recaptcha_qsencode ($data); + + $http_request = "POST $path HTTP/1.0\r\n"; + $http_request .= "Host: $host\r\n"; + $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n"; + $http_request .= "Content-Length: " . strlen($req) . "\r\n"; + $http_request .= "User-Agent: reCAPTCHA/PHP\r\n"; + $http_request .= "\r\n"; + $http_request .= $req; + + $response = ''; + if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) { + die ('Could not open socket'); + } + + fwrite($fs, $http_request); + + while ( !feof($fs) ) + $response .= fgets($fs, 1160); // One TCP-IP packet + fclose($fs); + $response = explode("\r\n\r\n", $response, 2); + + return $response; +} + + + +/** + * Gets the challenge HTML (javascript and non-javascript version). + * This is called from the browser, and the resulting reCAPTCHA HTML widget + * is embedded within the HTML form it was called from. + * @param string $pubkey A public key for reCAPTCHA + * @param string $error The error given by reCAPTCHA (optional, default is null) + * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false) + + * @return string - The HTML to be embedded in the user's form. + */ +function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false) +{ + if ($pubkey == null || $pubkey == '') { + die ("To use reCAPTCHA you must get an API key from https://www.google.com/recaptcha/admin/create"); + } + + if ($use_ssl) { + $server = RECAPTCHA_API_SECURE_SERVER; + } else { + $server = RECAPTCHA_API_SERVER; + } + + $errorpart = ""; + if ($error) { + $errorpart = "&error=" . $error; + } + return ' + + '; +} + + + + +/** + * A ReCaptchaResponse is returned from recaptcha_check_answer() + */ +class ReCaptchaResponse { + var $is_valid; + var $error; +} + + +/** + * Calls an HTTP POST function to verify if the user's guess was correct + * @param string $privkey + * @param string $remoteip + * @param string $challenge + * @param string $response + * @param array $extra_params an array of extra variables to post to the server + * @return ReCaptchaResponse + */ +function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array()) +{ + if ($privkey == null || $privkey == '') { + die ("To use reCAPTCHA you must get an API key from https://www.google.com/recaptcha/admin/create"); + } + + if ($remoteip == null || $remoteip == '') { + die ("For security reasons, you must pass the remote ip to reCAPTCHA"); + } + + + + //discard spam submissions + if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) { + $recaptcha_response = new ReCaptchaResponse(); + $recaptcha_response->is_valid = false; + $recaptcha_response->error = 'incorrect-captcha-sol'; + return $recaptcha_response; + } + + $response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify", + array ( + 'privatekey' => $privkey, + 'remoteip' => $remoteip, + 'challenge' => $challenge, + 'response' => $response + ) + $extra_params + ); + + $answers = explode ("\n", $response [1]); + $recaptcha_response = new ReCaptchaResponse(); + + if (trim ($answers [0]) == 'true') { + $recaptcha_response->is_valid = true; + } + else { + $recaptcha_response->is_valid = false; + $recaptcha_response->error = $answers [1]; + } + return $recaptcha_response; + +} + +/** + * gets a URL where the user can sign up for reCAPTCHA. If your application + * has a configuration page where you enter a key, you should provide a link + * using this function. + * @param string $domain The domain where the page is hosted + * @param string $appname The name of your application + */ +function recaptcha_get_signup_url ($domain = null, $appname = null) { + return "https://www.google.com/recaptcha/admin/create?" . _recaptcha_qsencode (array ('domains' => $domain, 'app' => $appname)); +} + +function _recaptcha_aes_pad($val) { + $block_size = 16; + $numpad = $block_size - (strlen ($val) % $block_size); + return str_pad($val, strlen ($val) + $numpad, chr($numpad)); +} + +/* Mailhide related code */ + +function _recaptcha_aes_encrypt($val,$ky) { + if (! function_exists ("mcrypt_encrypt")) { + die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed."); + } + $mode=MCRYPT_MODE_CBC; + $enc=MCRYPT_RIJNDAEL_128; + $val=_recaptcha_aes_pad($val); + return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); +} + + +function _recaptcha_mailhide_urlbase64 ($x) { + return strtr(base64_encode ($x), '+/', '-_'); +} + +/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */ +function recaptcha_mailhide_url($pubkey, $privkey, $email) { + if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) { + die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " . + "you can do so at http://www.google.com/recaptcha/mailhide/apikey"); + } + + + $ky = pack('H*', $privkey); + $cryptmail = _recaptcha_aes_encrypt ($email, $ky); + + return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail); +} + +/** + * gets the parts of the email to expose to the user. + * eg, given johndoe@example,com return ["john", "example.com"]. + * the email is then displayed as john...@example.com + */ +function _recaptcha_mailhide_email_parts ($email) { + $arr = preg_split("/@/", $email ); + + if (strlen ($arr[0]) <= 4) { + $arr[0] = substr ($arr[0], 0, 1); + } else if (strlen ($arr[0]) <= 6) { + $arr[0] = substr ($arr[0], 0, 3); + } else { + $arr[0] = substr ($arr[0], 0, 4); + } + return $arr; +} + +/** + * Gets html to display an email address given a public an private key. + * to get a key, go to: + * + * http://www.google.com/recaptcha/mailhide/apikey + */ +function recaptcha_mailhide_html($pubkey, $privkey, $email) { + $emailparts = _recaptcha_mailhide_email_parts ($email); + $url = recaptcha_mailhide_url ($pubkey, $privkey, $email); + + return htmlentities($emailparts[0]) . "...@" . htmlentities ($emailparts [1]); + +} + + +?> \ No newline at end of file diff --git a/administrator/components/com_k2/models/categories.php b/administrator/components/com_k2/models/categories.php new file mode 100644 index 0000000..8e1b3f3 --- /dev/null +++ b/administrator/components/com_k2/models/categories.php @@ -0,0 +1,647 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', 'c.ordering', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', '', 'word'); + $filter_trash = $mainframe->getUserStateFromRequest($option.$view.'filter_trash', 'filter_trash', 0, 'int'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', -1, 'int'); + $language = $mainframe->getUserStateFromRequest($option.$view.'language', 'language', '', 'string'); + $filter_category = $mainframe->getUserStateFromRequest($option.$view.'filter_category', 'filter_category', 0, 'int'); + + $query = "SELECT c.*, g.name AS groupname, exfg.name as extra_fields_group FROM #__k2_categories as c LEFT JOIN #__groups AS g ON g.id = c.access LEFT JOIN #__k2_extra_fields_groups AS exfg ON exfg.id = c.extraFieldsGroup WHERE c.id>0"; + + if (!$filter_trash) + { + $query .= " AND c.trash=0"; + } + + if ($search) + { + $escaped = K2_JVERSION == '15' ? $db->getEscaped($search, true) : $db->escape($search, true); + $query .= " AND LOWER( c.name ) LIKE ".$db->Quote('%'.$escaped.'%', false); + } + + if ($filter_state > -1) + { + $query .= " AND c.published={$filter_state}"; + } + if ($language) + { + $query .= " AND (c.language = ".$db->Quote($language)." OR c.language = '*')"; + } + + if ($filter_category) + { + K2Model::addIncludePath(JPATH_SITE.DS.'components'.DS.'com_k2'.DS.'models'); + $ItemlistModel = K2Model::getInstance('Itemlist', 'K2Model'); + $tree = $ItemlistModel->getCategoryTree($filter_category); + $query .= " AND c.id IN (".implode(',', $tree).")"; + } + + $query .= " ORDER BY {$filter_order} {$filter_order_Dir}"; + + if (K2_JVERSION != '15') + { + $query = JString::str_ireplace('#__groups', '#__viewlevels', $query); + $query = JString::str_ireplace('g.name AS groupname', 'g.title AS groupname', $query); + } + + $db->setQuery($query); + $rows = $db->loadObjectList(); + if (K2_JVERSION != '15') + { + foreach ($rows as $row) + { + $row->parent_id = $row->parent; + $row->title = $row->name; + } + } + $categories = array(); + + if ($search) + { + foreach ($rows as $row) + { + $row->treename = $row->name; + $categories[] = $row; + } + + } + else + { + if ($filter_category) + { + $db->setQuery('SELECT parent FROM #__k2_categories WHERE id = '.$filter_category); + $root = $db->loadResult(); + } + else + { + $root = 0; + } + $categories = $this->indentRows($rows, $root); + } + if (isset($categories)) + { + $total = count($categories); + } + else + { + $total = 0; + } + jimport('joomla.html.pagination'); + $pageNav = new JPagination($total, $limitstart, $limit); + $categories = @array_slice($categories, $pageNav->limitstart, $pageNav->limit); + foreach ($categories as $category) + { + $category->parameters = class_exists('JParameter') ? new JParameter($category->params) : new JRegistry($category->params); + if ($category->parameters->get('inheritFrom')) + { + $db->setQuery("SELECT name FROM #__k2_categories WHERE id = ".(int)$category->parameters->get('inheritFrom')); + $category->inheritFrom = $db->loadResult(); + } + else + { + $category->inheritFrom = ''; + } + } + return $categories; + } + + function getTotal() + { + + $mainframe = JFactory::getApplication(); + $option = JRequest::getCmd('option'); + $view = JRequest::getCmd('view'); + $db = JFactory::getDBO(); + $limit = $mainframe->getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.'.limitstart', 'limitstart', 0, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + $filter_trash = $mainframe->getUserStateFromRequest($option.$view.'filter_trash', 'filter_trash', 0, 'int'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', 1, 'int'); + $language = $mainframe->getUserStateFromRequest($option.$view.'language', 'language', '', 'string'); + $filter_category = $mainframe->getUserStateFromRequest($option.$view.'filter_category', 'filter_category', 0, 'int'); + + $query = "SELECT COUNT(*) FROM #__k2_categories WHERE id>0"; + + if (!$filter_trash) + { + $query .= " AND trash=0"; + } + + if ($search) + { + $escaped = K2_JVERSION == '15' ? $db->getEscaped($search, true) : $db->escape($search, true); + $query .= " AND LOWER( name ) LIKE ".$db->Quote('%'.$escaped.'%', false); + } + + if ($filter_state > -1) + { + $query .= " AND published={$filter_state}"; + } + + if ($language) + { + $query .= " AND (language = ".$db->Quote($language)." OR language = '*')"; + } + + if ($filter_category) + { + K2Model::addIncludePath(JPATH_SITE.DS.'components'.DS.'com_k2'.DS.'models'); + $ItemlistModel = K2Model::getInstance('Itemlist', 'K2Model'); + $tree = $ItemlistModel->getCategoryTree($filter_category); + $query .= " AND id IN (".implode(',', $tree).")"; + } + + $db->setQuery($query); + $total = $db->loadResult(); + return $total; + + } + + function indentRows(&$rows, $root = 0) + { + $children = array(); + if (count($rows)) + { + foreach ($rows as $v) + { + $pt = $v->parent; + $list = @$children[$pt] ? $children[$pt] : array(); + array_push($list, $v); + $children[$pt] = $list; + } + } + $categories = JHTML::_('menu.treerecurse', $root, '', array(), $children); + return $categories; + } + + function publish() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Category', 'Table'); + $row->load($id); + $row->publish($id, 1); + } + JPluginHelper::importPlugin('finder'); + $dispatcher = JDispatcher::getInstance(); + $dispatcher->trigger('onFinderChangeState', array('com_k2.category', $cid, 1)); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=categories'); + } + + function unpublish() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Category', 'Table'); + $row->load($id); + $row->publish($id, 0); + } + JPluginHelper::importPlugin('finder'); + $dispatcher = JDispatcher::getInstance(); + $dispatcher->trigger('onFinderChangeState', array('com_k2.category', $cid, 0)); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=categories'); + } + + function saveorder() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid', array(0), 'post', 'array'); + $total = count($cid); + $order = JRequest::getVar('order', array(0), 'post', 'array'); + JArrayHelper::toInteger($order, array(0)); + $groupings = array(); + for ($i = 0; $i < $total; $i++) + { + $row = JTable::getInstance('K2Category', 'Table'); + $row->load(( int )$cid[$i]); + $groupings[] = $row->parent; + if ($row->ordering != $order[$i]) + { + $row->ordering = $order[$i]; + if (!$row->store()) + { + JError::raiseError(500, $db->getErrorMsg()); + } + } + } + $params = JComponentHelper::getParams('com_k2'); + if (!$params->get('disableCompactOrdering')) + { + $groupings = array_unique($groupings); + foreach ($groupings as $group) + { + $row = JTable::getInstance('K2Category', 'Table'); + $row->reorder('parent = '.( int )$group.' AND trash=0'); + } + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + return true; + } + + function orderup() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $row = JTable::getInstance('K2Category', 'Table'); + $row->load($cid[0]); + $row->move(-1, 'parent = '.$row->parent.' AND trash=0'); + $params = JComponentHelper::getParams('com_k2'); + if (!$params->get('disableCompactOrdering')) + $row->reorder('parent = '.$row->parent.' AND trash=0'); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ORDERING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=categories', $msg); + } + + function orderdown() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $row = JTable::getInstance('K2Category', 'Table'); + $row->load($cid[0]); + $row->move(1, 'parent = '.$row->parent.' AND trash=0'); + $params = JComponentHelper::getParams('com_k2'); + if (!$params->get('disableCompactOrdering')) + $row->reorder('parent = '.$row->parent.' AND trash=0'); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ORDERING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=categories', $msg); + } + + function accessregistered() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $row = JTable::getInstance('K2Category', 'Table'); + $cid = JRequest::getVar('cid'); + $row->load($cid[0]); + $row->access = 1; + if (!$row->check()) + { + return $row->getError(); + } + if (!$row->store()) + { + return $row->getError(); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ACCESS_SETTING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=categories', $msg); + } + + function accessspecial() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $row = JTable::getInstance('K2Category', 'Table'); + $cid = JRequest::getVar('cid'); + $row->load($cid[0]); + $row->access = 2; + if (!$row->check()) + { + return $row->getError(); + } + if (!$row->store()) + { + return $row->getError(); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ACCESS_SETTING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=categories', $msg); + } + + function accesspublic() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $row = JTable::getInstance('K2Category', 'Table'); + $cid = JRequest::getVar('cid'); + $row->load($cid[0]); + $row->access = 0; + if (!$row->check()) + { + return $row->getError(); + } + if (!$row->store()) + { + return $row->getError(); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ACCESS_SETTING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=categories', $msg); + } + + function trash() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + $row = JTable::getInstance('K2Category', 'Table'); + JArrayHelper::toInteger($cid); + K2Model::addIncludePath(JPATH_SITE.DS.'components'.DS.'com_k2'.DS.'models'); + $model = K2Model::getInstance('Itemlist', 'K2Model'); + $categories = $model->getCategoryTree($cid); + $sql = @implode(',', $categories); + $db = JFactory::getDBO(); + $query = "UPDATE #__k2_categories SET trash=1 WHERE id IN ({$sql})"; + $db->setQuery($query); + $db->query(); + $query = "UPDATE #__k2_items SET trash=1 WHERE catid IN ({$sql})"; + $db->setQuery($query); + $db->query(); + + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=categories', JText::_('K2_CATEGORIES_MOVED_TO_TRASH')); + + } + + function restore() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + $warning = false; + $restored = array(); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Category', 'Table'); + $row->load($id); + if ((int)$row->parent == 0) + { + $row->trash = 0; + $row->store(); + $restored[] = $id; + } + else + { + $query = "SELECT COUNT(*) FROM #__k2_categories WHERE id={$row->parent} AND trash = 0"; + $db->setQuery($query); + $result = $db->loadResult(); + if ($result) + { + $row->trash = 0; + $row->store(); + $restored[] = $id; + } + else + { + $warning = true; + } + + } + + } + // Restore also the items of the categories + if (count($restored)) + { + JArrayHelper::toInteger($restored); + $db->setQuery('UPDATE #__k2_items SET trash = 0 WHERE catid IN ('.implode(',', $restored).') AND trash = 1'); + $db->query(); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + if ($warning) + $mainframe->enqueueMessage(JText::_('K2_SOME_OF_THE_CATEGORIES_HAVE_NOT_BEEN_RESTORED_BECAUSE_THEIR_PARENT_CATEGORY_IS_IN_TRASH'), 'notice'); + $mainframe->redirect('index.php?option=com_k2&view=categories', JText::_('K2_CATEGORIES_RESTORED')); + + } + + function remove() + { + + $mainframe = JFactory::getApplication(); + jimport('joomla.filesystem.file'); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + JArrayHelper::toInteger($cid); + JPluginHelper::importPlugin('finder'); + $dispatcher = JDispatcher::getInstance(); + $warningItems = false; + $warningChildren = false; + $cid = array_reverse($cid); + for ($i = 0; $i < sizeof($cid); $i++) + { + $row = JTable::getInstance('K2Category', 'Table'); + $row->load($cid[$i]); + + $query = "SELECT COUNT(*) FROM #__k2_items WHERE catid={$cid[$i]}"; + $db->setQuery($query); + $num = $db->loadResult(); + + if ($num > 0) + { + $warningItems = true; + } + + $query = "SELECT COUNT(*) FROM #__k2_categories WHERE parent={$cid[$i]}"; + $db->setQuery($query); + $children = $db->loadResult(); + + if ($children > 0) + { + $warningChildren = true; + } + + if ($children == 0 && $num == 0) + { + + if ($row->image) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'categories'.DS.$row->image); + } + $row->delete($cid[$i]); + $dispatcher->trigger('onFinderAfterDelete', array('com_k2.category', $row)); + + } + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + + if ($warningItems) + { + $mainframe->enqueueMessage(JText::_('K2_SOME_OF_THE_CATEGORIES_HAVE_NOT_BEEN_DELETED_BECAUSE_THEY_HAVE_ITEMS'), 'notice'); + } + if ($warningChildren) + { + $mainframe->enqueueMessage(JText::_('K2_SOME_OF_THE_CATEGORIES_HAVE_NOT_BEEN_DELETED_BECAUSE_THEY_HAVE_CHILD_CATEGORIES'), 'notice'); + } + + $mainframe->redirect('index.php?option=com_k2&view=categories', JText::_('K2_DELETE_COMPLETED')); + } + + function categoriesTree($row = NULL, $hideTrashed = false, $hideUnpublished = true) + { + + $db = JFactory::getDBO(); + if (isset($row->id)) + { + $idCheck = ' AND id != '.( int )$row->id; + } + else + { + $idCheck = null; + } + if (!isset($row->parent)) + { + if (is_null($row)) + { + $row = new stdClass; + } + $row->parent = 0; + } + $query = "SELECT m.* FROM #__k2_categories m WHERE id > 0 {$idCheck}"; + + if ($hideUnpublished) + { + $query .= " AND published=1 "; + } + + if ($hideTrashed) + { + $query .= " AND trash=0 "; + } + + $query .= " ORDER BY parent, ordering"; + $db->setQuery($query); + $mitems = $db->loadObjectList(); + $children = array(); + if ($mitems) + { + foreach ($mitems as $v) + { + if (K2_JVERSION != '15') + { + $v->title = $v->name; + $v->parent_id = $v->parent; + } + $pt = $v->parent; + $list = @$children[$pt] ? $children[$pt] : array(); + array_push($list, $v); + $children[$pt] = $list; + } + } + $list = JHTML::_('menu.treerecurse', 0, '', array(), $children, 9999, 0, 0); + $mitems = array(); + foreach ($list as $item) + { + $item->treename = JString::str_ireplace(' ', '- ', $item->treename); + + if ($item->trash) + $item->treename .= ' [**'.JText::_('K2_TRASHED_CATEGORY').'**]'; + if (!$item->published) + $item->treename .= ' [**'.JText::_('K2_UNPUBLISHED_CATEGORY').'**]'; + + $mitems[] = JHTML::_('select.option', $item->id, $item->treename); + } + return $mitems; + } + + function copy() + { + jimport('joomla.filesystem.file'); + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + JArrayHelper::toInteger($cid); + foreach ($cid as $id) + { + //Load source category + $category = JTable::getInstance('K2Category', 'Table'); + $category->load($id); + + //Save target category + $row = JTable::getInstance('K2Category', 'Table'); + $row = $category; + $row->id = NULL; + $row->name = JText::_('K2_COPY_OF').' '.$category->name; + $row->published = 0; + $row->store(); + //Target image + if ($category->image && JFile::exists(JPATH_SITE.DS.'media'.DS.'k2'.DS.'categories'.DS.$category->image)) + { + JFile::copy(JPATH_SITE.DS.'media'.DS.'k2'.DS.'categories'.DS.$category->image, JPATH_SITE.DS.'media'.DS.'k2'.DS.'categories'.DS.$row->id.'.jpg'); + $row->image = $row->id.'.jpg'; + $row->store(); + } + } + + $mainframe->redirect('index.php?option=com_k2&view=categories', JText::_('K2_COPY_COMPLETED')); + } + + function move() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $catid = JRequest::getInt('category'); + + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Category', 'Table'); + $row->load($id); + $row->parent = $catid; + $row->ordering = $row->getNextOrder('parent = '.$row->parent.' AND published = 1'); + $row->store(); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=categories', JText::_('K2_MOVE_COMPLETED')); + + } + +} diff --git a/administrator/components/com_k2/models/category.php b/administrator/components/com_k2/models/category.php new file mode 100644 index 0000000..2a6d4a2 --- /dev/null +++ b/administrator/components/com_k2/models/category.php @@ -0,0 +1,170 @@ +load($cid); + return $row; + } + + function save() + { + $mainframe = JFactory::getApplication(); + jimport('joomla.filesystem.file'); + require_once (JPATH_COMPONENT.DS.'lib'.DS.'class.upload.php'); + $row = JTable::getInstance('K2Category', 'Table'); + $params = JComponentHelper::getParams('com_k2'); + + if (!$row->bind(JRequest::get('post'))) + { + $mainframe->redirect('index.php?option=com_k2&view=categories', $row->getError(), 'error'); + } + + $isNew = ($row->id) ? false : true; + + //Trigger the finder before save event + $dispatcher = JDispatcher::getInstance(); + JPluginHelper::importPlugin('finder'); + $results = $dispatcher->trigger('onFinderBeforeSave', array('com_k2.category', $row, $isNew)); + + $row->description = JRequest::getVar('description', '', 'post', 'string', 2); + if ($params->get('xssFiltering')) + { + $filter = new JFilterInput( array(), array(), 1, 1, 0); + $row->description = $filter->clean($row->description); + } + + if (!$row->id) + { + $row->ordering = $row->getNextOrder('parent = '.$row->parent.' AND trash=0'); + } + + if (!$row->check()) + { + $mainframe->redirect('index.php?option=com_k2&view=category&cid='.$row->id, $row->getError(), 'error'); + } + + if (!$row->store()) + { + $mainframe->redirect('index.php?option=com_k2&view=categories', $row->getError(), 'error'); + } + + if (!$params->get('disableCompactOrdering')) + $row->reorder('parent = '.$row->parent.' AND trash=0'); + + if ((int)$params->get('imageMemoryLimit')) + { + ini_set('memory_limit', (int)$params->get('imageMemoryLimit').'M'); + } + + $files = JRequest::get('files'); + + $savepath = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'categories'.DS; + + $existingImage = JRequest::getVar('existingImage'); + if (($files['image']['error'] === 0 || $existingImage) && !JRequest::getBool('del_image')) + { + if ($files['image']['error'] === 0) + { + $image = $files['image']; + } + else + { + $image = JPATH_SITE.DS.JPath::clean($existingImage); + } + + $handle = new Upload($image); + if ($handle->uploaded) + { + $handle->file_auto_rename = false; + $handle->jpeg_quality = $params->get('imagesQuality', '85'); + $handle->file_overwrite = true; + $handle->file_new_name_body = $row->id; + $handle->image_resize = true; + $handle->image_ratio_y = true; + $handle->image_x = $params->get('catImageWidth', '100'); + $handle->Process($savepath); + if ($files['image']['error'] === 0) + $handle->Clean(); + } + else + { + $mainframe->redirect('index.php?option=com_k2&view=categories', $handle->error, 'error'); + } + $row->image = $handle->file_dst_name; + } + + if (JRequest::getBool('del_image')) + { + $currentRow = JTable::getInstance('K2Category', 'Table'); + $currentRow->load($row->id); + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'categories'.DS.$currentRow->image)) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'categories'.DS.$currentRow->image); + } + $row->image = ''; + } + + if (!$row->store()) + { + $mainframe->redirect('index.php?option=com_k2&view=categories', $row->getError(), 'error'); + } + + //Trigger the finder after save event + $dispatcher = JDispatcher::getInstance(); + JPluginHelper::importPlugin('finder'); + $results = $dispatcher->trigger('onFinderAfterSave', array('com_k2.category', $row, $isNew)); + + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + + switch(JRequest::getCmd('task')) + { + case 'apply' : + $msg = JText::_('K2_CHANGES_TO_CATEGORY_SAVED'); + $link = 'index.php?option=com_k2&view=category&cid='.$row->id; + break; + case 'saveAndNew' : + $msg = JText::_('K2_CATEGORY_SAVED'); + $link = 'index.php?option=com_k2&view=category'; + break; + case 'save' : + default : + $msg = JText::_('K2_CATEGORY_SAVED'); + $link = 'index.php?option=com_k2&view=categories'; + break; + } + $mainframe->redirect($link, $msg); + } + + function countCategoryItems($catid, $trash = 0) + { + + $db = JFactory::getDBO(); + $catid = (int)$catid; + $query = "SELECT COUNT(*) FROM #__k2_items WHERE catid={$catid} AND trash = ".(int)$trash; + $db->setQuery($query); + $result = $db->loadResult(); + return $result; + + } + +} diff --git a/administrator/components/com_k2/models/category.xml b/administrator/components/com_k2/models/category.xml new file mode 100644 index 0000000..669f4ed --- /dev/null +++ b/administrator/components/com_k2/models/category.xml @@ -0,0 +1,938 @@ + +
    + K2_CATEGORY_EDIT_FORM + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    +
    +
    diff --git a/administrator/components/com_k2/models/comments.php b/administrator/components/com_k2/models/comments.php new file mode 100644 index 0000000..4c807f1 --- /dev/null +++ b/administrator/components/com_k2/models/comments.php @@ -0,0 +1,313 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', 'c.id', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', 'DESC', 'word'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', -1, 'int'); + $filter_category = $mainframe->getUserStateFromRequest($option.$view.'filter_category', 'filter_category', 0, 'int'); + $filter_author = $mainframe->getUserStateFromRequest($option.$view.'filter_author', 'filter_author', 0, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + + $query = "SELECT c.*, i.title , i.catid, i.alias AS itemAlias, i.created_by, cat.alias AS catAlias, cat.name as catName FROM #__k2_comments AS c LEFT JOIN #__k2_items AS i ON c.itemID=i.id LEFT JOIN #__k2_categories AS cat ON cat.id=i.catid WHERE c.id>0"; + + if ($filter_state > - 1) { + $query .= " AND c.published={$filter_state}"; + } + + if ($filter_category) { + $query .= " AND i.catid={$filter_category}"; + } + + if ($filter_author) { + $query .= " AND i.created_by={$filter_author}"; + } + + if ($search) { + $escaped = K2_JVERSION == '15' ? $db->getEscaped($search, true) : $db->escape($search, true); + $query .= " AND LOWER( c.commentText ) LIKE ".$db->Quote('%'.$escaped.'%', false); + } + + if (!$filter_order) { + $filter_order = "c.commentDate"; + } + + $query .= " ORDER BY {$filter_order} {$filter_order_Dir}"; + $db->setQuery($query, $limitstart, $limit); + $rows = $db->loadObjectList(); + return $rows; + } + + function getTotal() { + + $mainframe = JFactory::getApplication(); + $option = JRequest::getCmd('option'); + $view = JRequest::getCmd('view'); + $db = JFactory::getDBO(); + $limit = $mainframe->getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.'.limitstart', 'limitstart', 0, 'int'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', 1, 'int'); + $filter_category = $mainframe->getUserStateFromRequest($option.$view.'filter_category', 'filter_category', 0, 'int'); + $filter_author = $mainframe->getUserStateFromRequest($option.$view.'filter_author', 'filter_author', 0, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + + $query = "SELECT COUNT(*) FROM #__k2_comments AS c LEFT JOIN #__k2_items AS i ON c.itemID=i.id WHERE c.id>0"; + + if ($filter_state > - 1) { + $query .= " AND c.published={$filter_state}"; + } + + if ($filter_category) { + $query .= " AND i.catid={$filter_category}"; + } + + if ($filter_author) { + $query .= " AND i.created_by={$filter_author}"; + } + + if ($search) { + $escaped = K2_JVERSION == '15' ? $db->getEscaped($search, true) : $db->escape($search, true); + $query .= " AND LOWER( c.commentText ) LIKE ".$db->Quote('%'.$escaped.'%', false); + } + + $db->setQuery($query); + $total = $db->loadresult(); + return $total; + } + + function publish() { + + $mainframe = JFactory::getApplication(); + $user = JFactory::getUser(); + $cid = JRequest::getVar('cid'); + if(!count($cid)){ + $cid[]=JRequest::getInt('commentID'); + } + + foreach ($cid as $id) { + $row = JTable::getInstance('K2Comment', 'Table'); + $row->load($id); + if($mainframe->isSite()){ + $item = JTable::getInstance('K2Item', 'Table'); + $item->load($row->itemID); + if ($item->created_by != $user->id) { + JError::raiseError(403, JText::_('K2_ALERTNOTAUTH')); + $mainframe->close(); + } + } + $row->publish($id, 1); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + if(JRequest::getCmd('format')=='raw'){ + echo 'true'; + $mainframe->close(); + } + $mainframe->redirect('index.php?option=com_k2&view=comments'); + } + + function unpublish() { + + $mainframe = JFactory::getApplication(); + $user = JFactory::getUser(); + $cid = JRequest::getVar('cid'); + foreach ($cid as $id) { + $row = JTable::getInstance('K2Comment', 'Table'); + $row->load($id); + if($mainframe->isSite()){ + $item = JTable::getInstance('K2Item', 'Table'); + $item->load($row->itemID); + if ($item->created_by != $user->id) { + JError::raiseError(403, JText::_('K2_ALERTNOTAUTH')); + $mainframe->close(); + } + } + $row->publish($id, 0); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=comments'); + } + + function remove() { + + $mainframe = JFactory::getApplication(); + $user = JFactory::getUser(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + if(!count($cid)){ + $cid[]=JRequest::getInt('commentID'); + } + foreach ($cid as $id) { + $row = JTable::getInstance('K2Comment', 'Table'); + $row->load($id); + if($mainframe->isSite()){ + $item = JTable::getInstance('K2Item', 'Table'); + $item->load($row->itemID); + if ($item->created_by != $user->id) { + JError::raiseError(403, JText::_('K2_ALERTNOTAUTH')); + $mainframe->close(); + } + } + $row->delete($id); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + if(JRequest::getCmd('format')=='raw'){ + echo 'true'; + $mainframe->close(); + } + $mainframe->redirect('index.php?option=com_k2&view=comments', JText::_('K2_DELETE_COMPLETED')); + } + + function deleteUnpublished() { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $user = JFactory::getUser(); + $userID = $user->id; + if($mainframe->isSite()){ + $query = "SELECT c.id FROM #__k2_comments AS c + LEFT JOIN #__k2_items AS i ON c.itemID=i.id + WHERE i.created_by = {$userID} AND c.published=0"; + $db->setQuery($query); + $ids = K2_JVERSION == '30' ? $db->loadColumn() : $db->loadResultArray(); + if (count($ids)){ + $query = "DELETE FROM #__k2_comments WHERE id IN(".implode(',', $ids).")"; + $db->setQuery($query); + $db->query(); + } + } + else { + $query = "DELETE FROM #__k2_comments WHERE published=0"; + $db->setQuery($query); + $db->query(); + } + + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=comments', JText::_('K2_DELETE_COMPLETED')); + } + + function save() { + + $mainframe = JFactory::getApplication(); + $user = JFactory::getUser(); + $db = JFactory::getDBO(); + $id = JRequest::getInt('commentID'); + $item = JTable::getInstance('K2Item', 'Table'); + $row = JTable::getInstance('K2Comment', 'Table'); + $row->load($id); + if($mainframe->isSite()){ + $item->load($row->itemID); + if ($item->created_by != $user->id) { + JError::raiseError(403, JText::_('K2_ALERTNOTAUTH')); + } + } + $row->commentText = JRequest::getVar('commentText', '', 'default', 'string', 4); + $row->store(); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $response = new JObject; + $response->comment = $row->commentText; + $response->message = JText::_('K2_COMMENT_SAVED'); + unset($response->_errors); + require_once (JPATH_COMPONENT_ADMINISTRATOR.DS.'lib'.DS.'JSON.php'); + $json = new Services_JSON; + echo $json->encode($response); + $mainframe->close(); + } + + function report(){ + $id = $this->getState('id'); + $name = JString::trim($this->getState('name')); + $reportReason = JString::trim($this->getState('reportReason')); + $params = &K2HelperUtilities::getParams('com_k2'); + $user = JFactory::getUser(); + $row = JTable::getInstance('K2Comment', 'Table'); + $row->load($id); + if(!$row->published){ + $this->setError(JText::_('K2_COMMENT_NOT_FOUND')); + return false; + } + if(empty($name)){ + $this->setError(JText::_('K2_PLEASE_TYPE_YOUR_NAME')); + return false; + } + if(empty($reportReason)){ + $this->setError(JText::_('K2_PLEASE_TYPE_THE_REPORT_REASON')); + return false; + } + if (($params->get('antispam') == 'recaptcha' || $params->get('antispam') == 'both') && $user->guest) { + if(!function_exists('_recaptcha_qsencode')) + { + require_once (JPATH_ADMINISTRATOR.DS.'components'.DS.'com_k2'.DS.'lib'.DS.'recaptchalib.php'); + } + $privatekey = $params->get('recaptcha_private_key'); + $resp = recaptcha_check_answer($privatekey, $_SERVER["REMOTE_ADDR"], $_POST["recaptcha_challenge_field"], $_POST["recaptcha_response_field"]); + if (!$resp->is_valid) { + $this->setError(JText::_('K2_THE_WORDS_YOU_TYPED_DID_NOT_MATCH_THE_ONES_DISPLAYED_PLEASE_TRY_AGAIN')); + return false; + } + } + + $mainframe = JFactory::getApplication(); + $mail = JFactory::getMailer(); + $senderEmail = $mainframe->getCfg('mailfrom'); + $senderName = $mainframe->getCfg('fromname'); + + $mail->setSender(array($senderEmail, $senderName)); + $mail->setSubject(JText::_('K2_COMMENT_REPORT')); + $mail->IsHTML(true); + + switch(substr(strtoupper(PHP_OS), 0, 3)) { + case 'WIN': + $mail->LE = "\r\n"; + break; + case 'MAC': + case 'DAR': + $mail->LE = "\r"; + default: + break; + } + + $body = " + ".JText::_('K2_NAME').": ".$name."
    + ".JText::_('K2_REPORT_REASON').": ".$reportReason."
    + ".JText::_('K2_COMMENT').": ".nl2br($row->commentText)."
    + "; + + $mail->setBody($body); + $mail->ClearAddresses(); + $mail->AddAddress($params->get('commentsReportRecipient', $mainframe->getCfg('mailfrom'))); + $mail->Send(); + + return true; + + } + +} diff --git a/administrator/components/com_k2/models/extrafield.php b/administrator/components/com_k2/models/extrafield.php new file mode 100644 index 0000000..4758d30 --- /dev/null +++ b/administrator/components/com_k2/models/extrafield.php @@ -0,0 +1,457 @@ +load($cid); + return $row; + } + + function save() + { + + $mainframe = JFactory::getApplication(); + $row = JTable::getInstance('K2ExtraField', 'Table'); + if (!$row->bind(JRequest::get('post'))) + { + $mainframe->redirect('index.php?option=com_k2&view=extrafields', $row->getError(), 'error'); + } + + $isNewGroup = JRequest::getInt('isNew'); + + if ($isNewGroup) + { + + $group = JTable::getInstance('K2ExtraFieldsGroup', 'Table'); + $group->set('name', JRequest::getVar('group')); + $group->store(); + $row->group = $group->id; + } + + if (!$row->id) + { + $row->ordering = $row->getNextOrder("`group` = {$row->group}"); + } + + $objects = array(); + $values = JRequest::getVar('option_value', null, 'default', 'none', 4); + $names = JRequest::getVar('option_name'); + $target = JRequest::getVar('option_target'); + $editor = JRequest::getVar('option_editor'); + $rows = JRequest::getVar('option_rows'); + $cols = JRequest::getVar('option_cols'); + $alias = JRequest::getWord('alias'); + $required = JRequest::getInt('required'); + $showNull = JRequest::getInt('showNull'); + $displayInFrontEnd = JRequest::getInt('displayInFrontEnd'); + + if (JString::strtolower($alias) == 'this') + { + $alias = ''; + } + + for ($i = 0; $i < sizeof($values); $i++) + { + $object = new JObject; + $object->set('name', $names[$i]); + + if ($row->type == 'select' || $row->type == 'multipleSelect' || $row->type == 'radio') + { + $object->set('value', $i + 1); + } + elseif ($row->type == 'link') + { + if (substr($values[$i], 0, 7) == 'http://') + { + $values[$i] = $values[$i]; + } + else + { + $values[$i] = 'http://'.$values[$i]; + } + $object->set('value', $values[$i]); + } + elseif ($row->type == 'csv') + { + $file = JRequest::getVar('csv_file', NULL, 'FILES'); + $csvFile = $file['tmp_name']; + if (!empty($csvFile) && JFile::getExt($file['name']) == 'csv') + { + $handle = @fopen($csvFile, 'r'); + $csvData = array(); + while (($data = fgetcsv($handle, 1000)) !== FALSE) + { + $csvData[] = $data; + } + fclose($handle); + $object->set('value', $csvData); + } + else + { + require_once (JPATH_COMPONENT.DS.'lib'.DS.'JSON.php'); + $json = new Services_JSON; + $object->set('value', $json->decode($values[$i])); + if (JRequest::getBool('K2ResetCSV')) + $object->set('value', null); + } + + } + elseif ($row->type == 'textarea') + { + $object->set('value', $values[$i]); + $object->set('editor', $editor[$i]); + $object->set('rows', $rows[$i]); + $object->set('cols', $cols[$i]); + } + elseif ($row->type == 'image') + { + $object->set('value', $values[$i]); + } + elseif ($row->type == 'header') + { + $object->set('value', JRequest::getString('name')); + $object->set('displayInFrontEnd', $displayInFrontEnd); + } + else + { + $object->set('value', $values[$i]); + } + + $object->set('target', $target[$i]); + $object->set('alias', $alias); + $object->set('required', $required); + $object->set('showNull', $showNull); + unset($object->_errors); + $objects[] = $object; + } + + require_once (JPATH_COMPONENT.DS.'lib'.DS.'JSON.php'); + $json = new Services_JSON; + $row->value = $json->encode($objects); + + if (!$row->check()) + { + $mainframe->redirect('index.php?option=com_k2&view=extrafield&cid='.$row->id, $row->getError(), 'error'); + } + + if (!$row->store()) + { + $mainframe->redirect('index.php?option=com_k2&view=extrafields', $row->getError(), 'error'); + } + + $params = JComponentHelper::getParams('com_k2'); + if (!$params->get('disableCompactOrdering')) + $row->reorder("`group` = {$row->group}"); + + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + + switch(JRequest::getCmd('task')) + { + case 'apply' : + $msg = JText::_('K2_CHANGES_TO_EXTRA_FIELD_SAVED'); + $link = 'index.php?option=com_k2&view=extrafield&cid='.$row->id; + break; + case 'save' : + default : + $msg = JText::_('K2_EXTRA_FIELD_SAVED'); + $link = 'index.php?option=com_k2&view=extrafields'; + break; + } + + $mainframe->redirect($link, $msg); + } + + function getExtraFieldsByGroup($group) + { + + $db = JFactory::getDBO(); + $group = (int)$group; + $query = "SELECT * FROM #__k2_extra_fields WHERE `group`={$group} AND published=1 ORDER BY ordering"; + $db->setQuery($query); + $rows = $db->loadObjectList(); + return $rows; + } + + function renderExtraField($extraField, $itemID = NULL) + { + + $mainframe = JFactory::getApplication(); + require_once (JPATH_COMPONENT_ADMINISTRATOR.DS.'lib'.DS.'JSON.php'); + $json = new Services_JSON; + + if (!is_null($itemID)) + { + $item = JTable::getInstance('K2Item', 'Table'); + $item->load($itemID); + } + + $defaultValues = $json->decode($extraField->value); + + foreach ($defaultValues as $value) + { + + $required = isset($value->required) ? $value->required : 0; + $showNull = isset($value->showNull) ? $value->showNull : 0; + + if ($extraField->type == 'textfield' || $extraField->type == 'csv' || $extraField->type == 'labels' || $extraField->type == 'date') + { + $active = $value->value; + } + elseif ($extraField->type == 'textarea') + { + $active[0] = $value->value; + $active[1] = $value->editor; + $active[2] = (int)$value->rows ? (int)$value->rows : 10; + $active[3] = (int)$value->cols ? (int)$value->cols : 40; + } + elseif ($extraField->type == 'link') + { + $active[0] = $value->name; + $active[1] = $value->value; + $active[2] = $value->target; + } + else + { + $active = ''; + } + + } + + if (!isset($active)) + { + $active = ''; + } + + if (isset($item)) + { + $currentValues = $json->decode($item->extra_fields); + if (count($currentValues)) + { + foreach ($currentValues as $value) + { + if ($value->id == $extraField->id) + { + if ($extraField->type == 'textarea') + { + $active[0] = $value->value; + } + else if ($extraField->type == 'date') + { + $active = (is_array($value->value)) ? $value->value[0] : $value->value; + } + else if ($extraField->type == 'header') + { + continue; + } + else + { + $active = $value->value; + } + } + } + } + + } + + $attributes = ''; + if ($required) + { + $attributes .= 'class="k2Required"'; + } + + if ($showNull && in_array($extraField->type, array( + 'select', + 'multipleSelect' + ))) + { + $nullOption = new stdClass; + $nullOption->name = JText::_('K2_PLEASE_SELECT'); + $nullOption->value = ''; + array_unshift($defaultValues, $nullOption); + } + + if (in_array($extraField->type, array( + 'textfield', + 'labels', + 'date', + 'image' + ))) + { + $active = htmlspecialchars($active, ENT_QUOTES, 'UTF-8'); + } + + switch ($extraField->type) + { + + case 'textfield' : + $output = ''; + break; + + case 'labels' : + $output = ' '.JText::_('K2_COMMA_SEPARATED_VALUES'); + break; + + case 'textarea' : + if ($active[1]) + { + if ($required) + { + $attributes = 'class="k2ExtraFieldEditor k2Required"'; + } + else + { + $attributes = 'class="k2ExtraFieldEditor"'; + } + } + $output = ''; + break; + + case 'select' : + $attributes .= ' id="'.$extraField->id.'.$extraField->id"'; + $output = JHTML::_('select.genericlist', $defaultValues, 'K2ExtraField_'.$extraField->id, $attributes, 'value', 'name', $active); + break; + + case 'multipleSelect' : + $attributes .= ' id="'.$extraField->id.'.$extraField->id" multiple="multiple"'; + $output = JHTML::_('select.genericlist', $defaultValues, 'K2ExtraField_'.$extraField->id.'[]', $attributes, 'value', 'name', $active); + break; + + case 'radio' : + if (!$active && isset($defaultValues[0])) + { + $active = $defaultValues[0]->value; + } + $output = JHTML::_('select.radiolist', $defaultValues, 'K2ExtraField_'.$extraField->id, $attributes, 'value', 'name', $active); + break; + + case 'link' : + $output = ''; + $output .= ''; + $output .= ''; + $output .= ''; + $output .= ''; + $targetOptions[] = JHTML::_('select.option', 'same', JText::_('K2_SAME_WINDOW')); + $targetOptions[] = JHTML::_('select.option', 'new', JText::_('K2_NEW_WINDOW')); + $targetOptions[] = JHTML::_('select.option', 'popup', JText::_('K2_CLASSIC_JAVASCRIPT_POPUP')); + $targetOptions[] = JHTML::_('select.option', 'lightbox', JText::_('K2_LIGHTBOX_POPUP')); + $output .= JHTML::_('select.genericlist', $targetOptions, 'K2ExtraField_'.$extraField->id.'[]', '', 'value', 'text', $active[2]); + break; + + case 'csv' : + if ($active) + { + $attributes = ''; + } + $output = ''; + + if (is_array($active) && count($active)) + { + $output .= ''; + $output .= ''; + foreach ($active as $key => $row) + { + $output .= ''; + foreach ($row as $cell) + { + $output .= ($key > 0) ? '' : ''; + } + $output .= ''; + } + $output .= '
    '.$cell.''.$cell.'
    '; + $output .= ''; + $output .= ''; + } + break; + + case 'date' : + $output = JHTML::_('calendar', $active, 'K2ExtraField_'.$extraField->id, 'K2ExtraField_'.$extraField->id, '%Y-%m-%d', $attributes); + break; + case 'image' : + $output = ' + '.JText::_('K2_SELECT').''; + break; + case 'header' : + $output = ''; + break; + } + + return $output; + + } + + function getExtraFieldInfo($fieldID) + { + + $db = JFactory::getDBO(); + $fieldID = (int)$fieldID; + $query = "SELECT * FROM #__k2_extra_fields WHERE published=1 AND id = ".$fieldID; + $db->setQuery($query, 0, 1); + $row = $db->loadObject(); + return $row; + } + + function getSearchValue($id, $currentValue) + { + + $row = JTable::getInstance('K2ExtraField', 'Table'); + $row->load($id); + + require_once (JPATH_COMPONENT_ADMINISTRATOR.DS.'lib'.DS.'JSON.php'); + $json = new Services_JSON; + $jsonObject = $json->decode($row->value); + + $value = ''; + if ($row->type == 'textfield' || $row->type == 'textarea') + { + $value = $currentValue; + } + else if ($row->type == 'multipleSelect') + { + foreach ($jsonObject as $option) + { + if (in_array($option->value, $currentValue)) + $value .= $option->name.' '; + } + } + else if ($row->type == 'link') + { + $value .= $currentValue[0].' '; + $value .= $currentValue[1].' '; + } + else if ($row->type == 'labels') + { + $parts = explode(',', $currentValue); + $value .= implode(' ', $parts); + } + else + { + foreach ($jsonObject as $option) + { + if ($option->value == $currentValue) + $value .= $option->name; + } + } + return $value; + } + +} diff --git a/administrator/components/com_k2/models/extrafields.php b/administrator/components/com_k2/models/extrafields.php new file mode 100644 index 0000000..71e47d3 --- /dev/null +++ b/administrator/components/com_k2/models/extrafields.php @@ -0,0 +1,361 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', 'groupname', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', 'ASC', 'word'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', -1, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + $filter_type = $mainframe->getUserStateFromRequest($option.$view.'filter_type', 'filter_type', '', 'string'); + $filter_group = $mainframe->getUserStateFromRequest($option.$view.'filter_group', 'filter_group', 0, 'int'); + + $query = "SELECT exf.*, exfg.name as groupname FROM #__k2_extra_fields AS exf LEFT JOIN #__k2_extra_fields_groups exfg ON exf.group=exfg.id WHERE exf.id>0"; + + if ($filter_state > -1) + { + $query .= " AND published={$filter_state}"; + } + + if ($search) + { + $escaped = K2_JVERSION == '15' ? $db->getEscaped($search, true) : $db->escape($search, true); + $query .= " AND LOWER( exf.name ) LIKE ".$db->Quote('%'.$escaped.'%', false); + } + + if ($filter_type) + { + $query .= " AND `type`=".$db->Quote($filter_type); + } + + if ($filter_group) + { + $query .= " AND `group`={$filter_group}"; + } + + if (!$filter_order) + { + $filter_order = '`group`'; + } + + if ($filter_order == 'ordering') + { + $query .= " ORDER BY `group`, ordering {$filter_order_Dir}"; + } + else + { + $query .= " ORDER BY {$filter_order} {$filter_order_Dir}, `group`, ordering"; + } + + $db->setQuery($query, $limitstart, $limit); + $rows = $db->loadObjectList(); + return $rows; + } + + function getTotal() + { + + $mainframe = JFactory::getApplication(); + $option = JRequest::getCmd('option'); + $view = JRequest::getCmd('view'); + $db = JFactory::getDBO(); + $limit = $mainframe->getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.'.limitstart', 'limitstart', 0, 'int'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', 1, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + $filter_type = $mainframe->getUserStateFromRequest($option.$view.'filter_type', 'filter_type', '', 'string'); + $filter_group = $mainframe->getUserStateFromRequest($option.$view.'filter_group', 'filter_group', '', 'string'); + + $query = "SELECT COUNT(*) FROM #__k2_extra_fields WHERE id>0"; + + if ($filter_state > -1) + { + $query .= " AND published={$filter_state}"; + } + + if ($search) + { + $escaped = K2_JVERSION == '15' ? $db->getEscaped($search, true) : $db->escape($search, true); + $query .= " AND LOWER( name ) LIKE ".$db->Quote('%'.$escaped.'%', false); + } + + if ($filter_type) + { + $query .= " AND `type`=".$db->Quote($filter_type); + } + + if ($filter_group) + { + $query .= " AND `group`=".$db->Quote($filter_group); + } + + $db->setQuery($query); + $total = $db->loadresult(); + return $total; + } + + function publish() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2ExtraField', 'Table'); + $row->load($id); + $row->publish($id, 1); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=extrafields'); + } + + function unpublish() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2ExtraField', 'Table'); + $row->load($id); + $row->publish($id, 0); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=extrafields'); + } + + function saveorder() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid', array(0), 'post', 'array'); + $total = count($cid); + $order = JRequest::getVar('order', array(0), 'post', 'array'); + JArrayHelper::toInteger($order, array(0)); + $groupings = array(); + for ($i = 0; $i < $total; $i++) + { + $row = JTable::getInstance('K2ExtraField', 'Table'); + $row->load((int)$cid[$i]); + $groupings[] = $row->group; + if ($row->ordering != $order[$i]) + { + $row->ordering = $order[$i]; + if (!$row->store()) + { + JError::raiseError(500, $db->getErrorMsg()); + } + } + } + $params = JComponentHelper::getParams('com_k2'); + if (!$params->get('disableCompactOrdering')) + { + $groupings = array_unique($groupings); + foreach ($groupings as $group) + { + $row = JTable::getInstance('K2ExtraField', 'Table'); + $row->reorder("`group` = {$group}"); + } + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + return true; + } + + function orderup() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $row = JTable::getInstance('K2ExtraField', 'Table'); + $row->load($cid[0]); + $row->move(-1, "`group` = '{$row->group}'"); + $params = JComponentHelper::getParams('com_k2'); + if (!$params->get('disableCompactOrdering')) + $row->reorder("`group` = '{$row->group}'"); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ORDERING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=extrafields', $msg); + } + + function orderdown() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $row = JTable::getInstance('K2ExtraField', 'Table'); + $row->load($cid[0]); + $row->move(1, "`group` = '{$row->group}'"); + $params = JComponentHelper::getParams('com_k2'); + if (!$params->get('disableCompactOrdering')) + $row->reorder("`group` = '{$row->group}'"); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ORDERING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=extrafields', $msg); + } + + function remove() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2ExtraField', 'Table'); + $row->load($id); + $row->delete($id); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=extrafields', JText::_('K2_DELETE_COMPLETED')); + } + + function getExtraFieldsGroup() + { + + $cid = JRequest::getVar('cid'); + $row = JTable::getInstance('K2ExtraFieldsGroup', 'Table'); + $row->load($cid); + return $row; + } + + function getGroups($filter = false) + { + + $mainframe = JFactory::getApplication(); + $option = JRequest::getCmd('option'); + $view = JRequest::getCmd('view'); + $limit = $mainframe->getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $db = JFactory::getDBO(); + $query = "SELECT * FROM #__k2_extra_fields_groups ORDER BY `name`"; + if ($filter) + { + $db->setQuery($query); + } + else + { + $db->setQuery($query, $limitstart, $limit); + } + + $rows = $db->loadObjectList(); + for ($i = 0; $i < sizeof($rows); $i++) + { + $query = "SELECT name FROM #__k2_categories WHERE extraFieldsGroup=".(int)$rows[$i]->id; + $db->setQuery($query); + $categories = K2_JVERSION == '30' ? $db->loadColumn() : $db->loadResultArray(); + if (is_array($categories)) + { + $rows[$i]->categories = implode(', ', $categories); + } + else + { + $rows[$i]->categories = ''; + } + + } + return $rows; + } + + function getTotalGroups() + { + + $db = JFactory::getDBO(); + $query = "SELECT COUNT(*) FROM #__k2_extra_fields_groups"; + $db->setQuery($query); + $total = $db->loadResult(); + return $total; + } + + function saveGroup() + { + + $mainframe = JFactory::getApplication(); + $id = JRequest::getInt('id'); + $row = JTable::getInstance('K2ExtraFieldsGroup', 'Table'); + if (!$row->bind(JRequest::get('post'))) + { + $mainframe->redirect('index.php?option=com_k2&view=extrafieldsgroups', $row->getError(), 'error'); + } + + if (!$row->check()) + { + $mainframe->redirect('index.php?option=com_k2&view=extrafieldsgroup&cid='.$row->id, $row->getError(), 'error'); + } + + if (!$row->store()) + { + $mainframe->redirect('index.php?option=com_k2&view=extrafieldsgroup', $row->getError(), 'error'); + } + + switch(JRequest::getCmd('task')) + { + case 'apply' : + $msg = JText::_('K2_CHANGES_TO_GROUP_SAVED'); + $link = 'index.php?option=com_k2&view=extrafieldsgroup&cid='.$row->id; + break; + case 'save' : + default : + $msg = JText::_('K2_GROUP_SAVED'); + $link = 'index.php?option=com_k2&view=extrafieldsgroups'; + break; + } + + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect($link, $msg); + } + + function removeGroups() + { + + $mainframe = JFactory::getApplication(); + $db = &JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + JArrayHelper::toInteger($cid); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2ExtraFieldsGroup', 'Table'); + $row->load($id); + $query = "DELETE FROM #__k2_extra_fields WHERE `group`={$id}"; + $db->setQuery($query); + $db->query(); + $row->delete($id); + } + $cache = &JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=extrafieldsgroups', JText::_('K2_DELETE_COMPLETED')); + } + +} diff --git a/administrator/components/com_k2/models/item.php b/administrator/components/com_k2/models/item.php new file mode 100644 index 0000000..30791a0 --- /dev/null +++ b/administrator/components/com_k2/models/item.php @@ -0,0 +1,1323 @@ +load($cid); + return $row; + } + + function save($front = false) + { + + $mainframe = JFactory::getApplication(); + jimport('joomla.filesystem.file'); + jimport('joomla.filesystem.folder'); + jimport('joomla.filesystem.archive'); + require_once (JPATH_COMPONENT_ADMINISTRATOR.DS.'lib'.DS.'class.upload.php'); + $db = JFactory::getDBO(); + $user = JFactory::getUser(); + $row = JTable::getInstance('K2Item', 'Table'); + $params = JComponentHelper::getParams('com_k2'); + $nullDate = $db->getNullDate(); + + if (!$row->bind(JRequest::get('post'))) + { + $mainframe->redirect('index.php?option=com_k2&view=items', $row->getError(), 'error'); + } + + if ($front && $row->id == NULL) + { + JLoader::register('K2HelperPermissions', JPATH_SITE.DS.'components'.DS.'com_k2'.DS.'helpers'.DS.'permissions.php'); + if (!K2HelperPermissions::canAddItem($row->catid)) + { + $mainframe->redirect('index.php?option=com_k2&view=item&task=add&tmpl=component', JText::_('K2_YOU_ARE_NOT_ALLOWED_TO_POST_TO_THIS_CATEGORY_SAVE_FAILED'), 'error'); + } + } + + ($row->id) ? $isNew = false : $isNew = true; + + if ($params->get('mergeEditors')) + { + $text = JRequest::getVar('text', '', 'post', 'string', 2); + if ($params->get('xssFiltering')) + { + $filter = new JFilterInput( array(), array(), 1, 1, 0); + $text = $filter->clean($text); + } + $pattern = '##i'; + $tagPos = preg_match($pattern, $text); + if ($tagPos == 0) + { + $row->introtext = $text; + $row->fulltext = ''; + } + else + list($row->introtext, $row->fulltext) = preg_split($pattern, $text, 2); + } + else + { + $row->introtext = JRequest::getVar('introtext', '', 'post', 'string', 2); + $row->fulltext = JRequest::getVar('fulltext', '', 'post', 'string', 2); + if ($params->get('xssFiltering')) + { + $filter = new JFilterInput( array(), array(), 1, 1, 0); + $row->introtext = $filter->clean($row->introtext); + $row->fulltext = $filter->clean($row->fulltext); + } + } + + if ($row->id) + { + $datenow = JFactory::getDate(); + $row->modified = K2_JVERSION == '15' ? $datenow->toMySQL() : $datenow->toSql(); + $row->modified_by = $user->get('id'); + } + else + { + $row->ordering = $row->getNextOrder("catid = {$row->catid} AND trash = 0"); + if ($row->featured) + $row->featured_ordering = $row->getNextOrder("featured = 1 AND trash = 0", 'featured_ordering'); + } + + $row->created_by = $row->created_by ? $row->created_by : $user->get('id'); + + if ($front) + { + $K2Permissions = K2Permissions::getInstance(); + if (!$K2Permissions->permissions->get('editAll')) + { + $row->created_by = $user->get('id'); + } + } + + if ($row->created && strlen(trim($row->created)) <= 10) + { + $row->created .= ' 00:00:00'; + } + + $config = JFactory::getConfig(); + $tzoffset = K2_JVERSION == '30' ? $config->get('offset') : $config->getValue('config.offset'); + $date = JFactory::getDate($row->created, $tzoffset); + $row->created = K2_JVERSION == '15' ? $date->toMySQL() : $date->toSql(); + + if (strlen(trim($row->publish_up)) <= 10) + { + $row->publish_up .= ' 00:00:00'; + } + + $date = JFactory::getDate($row->publish_up, $tzoffset); + $row->publish_up = K2_JVERSION == '15' ? $date->toMySQL() : $date->toSql(); + + if (trim($row->publish_down) == JText::_('K2_NEVER') || trim($row->publish_down) == '') + { + $row->publish_down = $nullDate; + } + else + { + if (strlen(trim($row->publish_down)) <= 10) + { + $row->publish_down .= ' 00:00:00'; + } + $date = JFactory::getDate($row->publish_down, $tzoffset); + $row->publish_down = K2_JVERSION == '15' ? $date->toMySQL() : $date->toSql(); + } + + $metadata = JRequest::getVar('meta', null, 'post', 'array'); + if (is_array($metadata)) + { + $txt = array(); + foreach ($metadata as $k => $v) + { + if ($k == 'description') + { + $row->metadesc = $v; + } + elseif ($k == 'keywords') + { + $row->metakey = $v; + } + else + { + $txt[] = "$k=$v"; + } + } + $row->metadata = implode("\n", $txt); + } + + if (!$row->check()) + { + $mainframe->redirect('index.php?option=com_k2&view=item&cid='.$row->id, $row->getError(), 'error'); + } + + $dispatcher = JDispatcher::getInstance(); + JPluginHelper::importPlugin('k2'); + $result = $dispatcher->trigger('onBeforeK2Save', array( + &$row, + $isNew + )); + if (in_array(false, $result, true)) + { + JError::raiseError(500, $row->getError()); + return false; + } + + //Trigger the finder before save event + $dispatcher = JDispatcher::getInstance(); + JPluginHelper::importPlugin('finder'); + $results = $dispatcher->trigger('onFinderBeforeSave', array( + 'com_k2.item', + $row, + $isNew + )); + + // Try to save the video if there is no need to wait for item ID + if (!JRequest::getBool('del_video')) + { + if (!isset($files['video'])) + { + + if (JRequest::getVar('remoteVideo')) + { + $fileurl = JRequest::getVar('remoteVideo'); + $filetype = JFile::getExt($fileurl); + $row->video = '{'.$filetype.'remote}'.$fileurl.'{/'.$filetype.'remote}'; + } + + if (JRequest::getVar('videoID')) + { + $provider = JRequest::getWord('videoProvider'); + $videoID = JRequest::getVar('videoID'); + $row->video = '{'.$provider.'}'.$videoID.'{/'.$provider.'}'; + } + + if (JRequest::getVar('embedVideo', '', 'post', 'string', JREQUEST_ALLOWRAW)) + { + $row->video = JRequest::getVar('embedVideo', '', 'post', 'string', JREQUEST_ALLOWRAW); + } + } + } + + // JoomFish! Front-end editing compatibility + if ($mainframe->isSite() && JFile::exists(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_joomfish'.DS.'joomfish.php')) + { + if (version_compare(phpversion(), '5.0') < 0) + { + $tmpRow = $row; + } + else + { + $tmpRow = clone($row); + } + } + + if (!$row->store()) + { + $mainframe->redirect('index.php?option=com_k2&view=items', $row->getError(), 'error'); + } + + // JoomFish! Front-end editing compatibility + if ($mainframe->isSite() && JFile::exists(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_joomfish'.DS.'joomfish.php')) + { + $itemID = $row->id; + $row = $tmpRow; + $row->id = $itemID; + } + + if (!$params->get('disableCompactOrdering')) + { + $row->reorder("catid = {$row->catid} AND trash = 0"); + } + if ($row->featured && !$params->get('disableCompactOrdering')) + { + $row->reorder("featured = 1 AND trash = 0", 'featured_ordering'); + } + $files = JRequest::get('files'); + + //Image + if ((int)$params->get('imageMemoryLimit')) + { + ini_set('memory_limit', (int)$params->get('imageMemoryLimit').'M'); + } + $existingImage = JRequest::getVar('existingImage'); + if (($files['image']['error'] === 0 || $existingImage) && !JRequest::getBool('del_image')) + { + + if ($files['image']['error'] === 0) + { + $image = $files['image']; + } + else + { + $image = JPATH_SITE.DS.JPath::clean($existingImage); + } + + $handle = new Upload($image); + $handle->allowed = array('image/*'); + + if ($handle->uploaded) + { + + //Image params + $category = JTable::getInstance('K2Category', 'Table'); + $category->load($row->catid); + $cparams = class_exists('JParameter') ? new JParameter($category->params) : new JRegistry($category->params); + + if ($cparams->get('inheritFrom')) + { + $masterCategoryID = $cparams->get('inheritFrom'); + $query = "SELECT * FROM #__k2_categories WHERE id=".(int)$masterCategoryID; + $db->setQuery($query, 0, 1); + $masterCategory = $db->loadObject(); + $cparams = class_exists('JParameter') ? new JParameter($masterCategory->params) : new JRegistry($masterCategory->params); + } + + $params->merge($cparams); + + //Original image + $savepath = JPATH_SITE.DS.'media'.DS.'k2'.DS.'items'.DS.'src'; + $handle->image_convert = 'jpg'; + $handle->jpeg_quality = 100; + $handle->file_auto_rename = false; + $handle->file_overwrite = true; + $handle->file_new_name_body = md5("Image".$row->id); + $handle->Process($savepath); + + $filename = $handle->file_dst_name_body; + $savepath = JPATH_SITE.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'; + + //XLarge image + $handle->image_resize = true; + $handle->image_ratio_y = true; + $handle->image_convert = 'jpg'; + $handle->jpeg_quality = $params->get('imagesQuality'); + $handle->file_auto_rename = false; + $handle->file_overwrite = true; + $handle->file_new_name_body = $filename.'_XL'; + if (JRequest::getInt('itemImageXL')) + { + $imageWidth = JRequest::getInt('itemImageXL'); + } + else + { + $imageWidth = $params->get('itemImageXL', '800'); + } + $handle->image_x = $imageWidth; + $handle->Process($savepath); + + //Large image + $handle->image_resize = true; + $handle->image_ratio_y = true; + $handle->image_convert = 'jpg'; + $handle->jpeg_quality = $params->get('imagesQuality'); + $handle->file_auto_rename = false; + $handle->file_overwrite = true; + $handle->file_new_name_body = $filename.'_L'; + if (JRequest::getInt('itemImageL')) + { + $imageWidth = JRequest::getInt('itemImageL'); + } + else + { + $imageWidth = $params->get('itemImageL', '600'); + } + $handle->image_x = $imageWidth; + $handle->Process($savepath); + + //Medium image + $handle->image_resize = true; + $handle->image_ratio_y = true; + $handle->image_convert = 'jpg'; + $handle->jpeg_quality = $params->get('imagesQuality'); + $handle->file_auto_rename = false; + $handle->file_overwrite = true; + $handle->file_new_name_body = $filename.'_M'; + if (JRequest::getInt('itemImageM')) + { + $imageWidth = JRequest::getInt('itemImageM'); + } + else + { + $imageWidth = $params->get('itemImageM', '400'); + } + $handle->image_x = $imageWidth; + $handle->Process($savepath); + + //Small image + $handle->image_resize = true; + $handle->image_ratio_y = true; + $handle->image_convert = 'jpg'; + $handle->jpeg_quality = $params->get('imagesQuality'); + $handle->file_auto_rename = false; + $handle->file_overwrite = true; + $handle->file_new_name_body = $filename.'_S'; + if (JRequest::getInt('itemImageS')) + { + $imageWidth = JRequest::getInt('itemImageS'); + } + else + { + $imageWidth = $params->get('itemImageS', '200'); + } + $handle->image_x = $imageWidth; + $handle->Process($savepath); + + //XSmall image + $handle->image_resize = true; + $handle->image_ratio_y = true; + $handle->image_convert = 'jpg'; + $handle->jpeg_quality = $params->get('imagesQuality'); + $handle->file_auto_rename = false; + $handle->file_overwrite = true; + $handle->file_new_name_body = $filename.'_XS'; + if (JRequest::getInt('itemImageXS')) + { + $imageWidth = JRequest::getInt('itemImageXS'); + } + else + { + $imageWidth = $params->get('itemImageXS', '100'); + } + $handle->image_x = $imageWidth; + $handle->Process($savepath); + + //Generic image + $handle->image_resize = true; + $handle->image_ratio_y = true; + $handle->image_convert = 'jpg'; + $handle->jpeg_quality = $params->get('imagesQuality'); + $handle->file_auto_rename = false; + $handle->file_overwrite = true; + $handle->file_new_name_body = $filename.'_Generic'; + $imageWidth = $params->get('itemImageGeneric', '300'); + $handle->image_x = $imageWidth; + $handle->Process($savepath); + + if ($files['image']['error'] === 0) + $handle->Clean(); + + } + else + { + $mainframe->redirect('index.php?option=com_k2&view=items', $handle->error, 'error'); + } + + } + + if (JRequest::getBool('del_image')) + { + + $current = JTable::getInstance('K2Item', 'Table'); + $current->load($row->id); + $filename = md5("Image".$current->id); + + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'src'.DS.$filename.'.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'src'.DS.$filename.'.jpg'); + } + + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.$filename.'_XS.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.$filename.'_XS.jpg'); + } + + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.$filename.'_S.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.$filename.'_S.jpg'); + } + + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.$filename.'_M.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.$filename.'_M.jpg'); + } + + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.$filename.'_L.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.$filename.'_L.jpg'); + } + + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.$filename.'_XL.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.$filename.'_XL.jpg'); + } + + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.$filename.'_Generic.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.$filename.'_Generic.jpg'); + } + + $row->image_caption = ''; + $row->image_credits = ''; + + } + + //Attachments + $attachments = JRequest::getVar('attachment_file', NULL, 'FILES', 'array'); + $attachments_names = JRequest::getVar('attachment_name', '', 'POST', 'array'); + $attachments_titles = JRequest::getVar('attachment_title', '', 'POST', 'array'); + $attachments_title_attributes = JRequest::getVar('attachment_title_attribute', '', 'POST', 'array'); + $attachments_existing_files = JRequest::getVar('attachment_existing_file', '', 'POST', 'array'); + + $attachmentFiles = array(); + + if (count($attachments)) + { + + foreach ($attachments as $k => $l) + { + foreach ($l as $i => $v) + { + if (!array_key_exists($i, $attachmentFiles)) + $attachmentFiles[$i] = array(); + $attachmentFiles[$i][$k] = $v; + } + + } + + $path = $params->get('attachmentsFolder', NULL); + if (is_null($path)) + { + $savepath = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'attachments'; + } + else + { + $savepath = $path; + } + + $counter = 0; + + foreach ($attachmentFiles as $key => $file) + { + + if ($file["tmp_name"] || $attachments_existing_files[$key]) + { + if ($attachments_existing_files[$key]) + { + $src = JPATH_SITE.DS.JPath::clean($attachments_existing_files[$key]); + $dest = $savepath.DS.basename($src); + if (JFile::exists($dest)) + { + $existingFileName = JFile::getName($dest); + $ext = JFile::getExt($existingFileName); + $basename = JFile::stripExt($existingFileName); + $newFilename = $basename.'_'.time().'.'.$ext; + $dest = $savepath.DS.$newFilename; + } + JFile::copy($src, $dest); + $attachment = JTable::getInstance('K2Attachment', 'Table'); + $attachment->itemID = $row->id; + $attachment->filename = $dest; + $attachment->title = ( empty($attachments_titles[$counter])) ? $filename : $attachments_titles[$counter]; + $attachment->titleAttribute = ( empty($attachments_title_attributes[$counter])) ? $filename : $attachments_title_attributes[$counter]; + $attachment->store(); + } + else + { + $handle = new Upload($file); + if ($handle->uploaded) + { + $handle->file_auto_rename = true; + $handle->allowed[] = 'application/x-zip'; + $handle->allowed[] = 'application/download'; + $handle->Process($savepath); + $filename = $handle->file_dst_name; + $handle->Clean(); + $attachment = JTable::getInstance('K2Attachment', 'Table'); + $attachment->itemID = $row->id; + $attachment->filename = $filename; + $attachment->title = ( empty($attachments_titles[$counter])) ? $filename : $attachments_titles[$counter]; + $attachment->titleAttribute = ( empty($attachments_title_attributes[$counter])) ? $filename : $attachments_title_attributes[$counter]; + $attachment->store(); + } + else + { + $mainframe->redirect('index.php?option=com_k2&view=items', $handle->error, 'error'); + } + + } + + } + + $counter++; + } + + } + + //Gallery + $flickrGallery = JRequest::getVar('flickrGallery'); + if ($flickrGallery) + { + $row->gallery = '{gallery}'.$flickrGallery.'{/gallery}'; + } + + if (isset($files['gallery']) && $files['gallery']['error'] == 0 && !JRequest::getBool('del_gallery')) + { + $handle = new Upload($files['gallery']); + $handle->file_auto_rename = true; + $savepath = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'galleries'; + $handle->allowed = array( + "application/download", + "application/rar", + "application/x-rar-compressed", + "application/arj", + "application/gnutar", + "application/x-bzip", + "application/x-bzip2", + "application/x-compressed", + "application/x-gzip", + "application/x-zip-compressed", + "application/zip", + "multipart/x-zip", + "multipart/x-gzip", + "application/x-unknown", + "application/x-zip" + ); + + if ($handle->uploaded) + { + + $handle->Process($savepath); + $handle->Clean(); + + if (JFolder::exists($savepath.DS.$row->id)) + { + JFolder::delete($savepath.DS.$row->id); + } + + if (!JArchive::extract($savepath.DS.$handle->file_dst_name, $savepath.DS.$row->id)) + { + $mainframe->redirect('index.php?option=com_k2&view=items', JText::_('K2_GALLERY_UPLOAD_ERROR_CANNOT_EXTRACT_ARCHIVE'), 'error'); + } + else + { + $row->gallery = '{gallery}'.$row->id.'{/gallery}'; + } + JFile::delete($savepath.DS.$handle->file_dst_name); + $handle->Clean(); + + } + else + { + $mainframe->redirect('index.php?option=com_k2&view=items', $handle->error, 'error'); + } + } + + if (JRequest::getBool('del_gallery')) + { + + $current = JTable::getInstance('K2Item', 'Table'); + $current->load($row->id); + + if (JFolder::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'galleries'.DS.$current->id)) + { + JFolder::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'galleries'.DS.$current->id); + } + $row->gallery = ''; + } + + //Video + if (!JRequest::getBool('del_video')) + { + if (isset($files['video']) && $files['video']['error'] == 0) + { + + $videoExtensions = array( + "flv", + "mp4", + "ogv", + "webm", + "f4v", + "m4v", + "3gp", + "3g2", + "mov", + "mpeg", + "mpg", + "avi", + "wmv", + "divx" + ); + $audioExtensions = array( + "mp3", + "aac", + "m4a", + "ogg", + "wma" + ); + $validExtensions = array_merge($videoExtensions, $audioExtensions); + $filetype = JFile::getExt($files['video']['name']); + + if (!in_array($filetype, $validExtensions)) + { + $mainframe->redirect('index.php?option=com_k2&view=items', JText::_('K2_INVALID_VIDEO_FILE'), 'error'); + } + + if (in_array($filetype, $videoExtensions)) + { + $savepath = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'videos'; + } + else + { + $savepath = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'audio'; + } + + $filename = JFile::stripExt($files['video']['name']); + + JFile::upload($files['video']['tmp_name'], $savepath.DS.$row->id.'.'.$filetype); + $filetype = JFile::getExt($files['video']['name']); + $row->video = '{'.$filetype.'}'.$row->id.'{/'.$filetype.'}'; + + } + + } + else + { + + $current = JTable::getInstance('K2Item', 'Table'); + $current->load($row->id); + + preg_match_all("#^{(.*?)}(.*?){#", $current->video, $matches, PREG_PATTERN_ORDER); + $videotype = $matches[1][0]; + $videofile = $matches[2][0]; + + if (in_array($videotype, $videoExtensions)) + { + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'videos'.DS.$videofile.'.'.$videotype)) + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'videos'.DS.$videofile.'.'.$videotype); + } + + if (in_array($videotype, $audioExtensions)) + { + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'audio'.DS.$videofile.'.'.$videotype)) + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'audio'.DS.$videofile.'.'.$videotype); + } + + $row->video = ''; + $row->video_caption = ''; + $row->video_credits = ''; + } + + //Extra fields + $objects = array(); + $variables = JRequest::get('post', 2); + foreach ($variables as $key => $value) + { + if (( bool )JString::stristr($key, 'K2ExtraField_')) + { + $object = new JObject; + $object->set('id', JString::substr($key, 13)); + if (is_string($value)) + { + $value = trim($value); + } + $object->set('value', $value); + unset($object->_errors); + $objects[] = $object; + } + } + + $csvFiles = JRequest::get('files'); + foreach ($csvFiles as $key => $file) + { + if (( bool )JString::stristr($key, 'K2ExtraField_')) + { + $object = new JObject; + $object->set('id', JString::substr($key, 13)); + $csvFile = $file['tmp_name'][0]; + if (!empty($csvFile) && JFile::getExt($file['name'][0]) == 'csv') + { + $handle = @fopen($csvFile, 'r'); + $csvData = array(); + while (($data = fgetcsv($handle, 1000)) !== FALSE) + { + $csvData[] = $data; + } + fclose($handle); + $object->set('value', $csvData); + } + else + { + require_once (JPATH_COMPONENT_ADMINISTRATOR.DS.'lib'.DS.'JSON.php'); + $json = new Services_JSON; + $object->set('value', $json->decode(JRequest::getVar('K2CSV_'.$object->id))); + if (JRequest::getBool('K2ResetCSV_'.$object->id)) + $object->set('value', null); + } + unset($object->_errors); + $objects[] = $object; + } + } + + require_once (JPATH_COMPONENT_ADMINISTRATOR.DS.'lib'.DS.'JSON.php'); + $json = new Services_JSON; + $row->extra_fields = $json->encode($objects); + + require_once (JPATH_COMPONENT_ADMINISTRATOR.DS.'models'.DS.'extrafield.php'); + $extraFieldModel = K2Model::getInstance('ExtraField', 'K2Model'); + $row->extra_fields_search = ''; + + foreach ($objects as $object) + { + $row->extra_fields_search .= $extraFieldModel->getSearchValue($object->id, $object->value); + $row->extra_fields_search .= ' '; + } + + //Tags + if ($user->gid < 24 && $params->get('lockTags')) + $params->set('taggingSystem', 0); + $db = JFactory::getDBO(); + $query = "DELETE FROM #__k2_tags_xref WHERE itemID={intval($row->id)}"; + $db->setQuery($query); + $db->query(); + + if ($params->get('taggingSystem')) + { + + if ($user->gid < 24 && $params->get('lockTags')) + JError::raiseError(403, JText::_('K2_ALERTNOTAUTH')); + + $tags = JRequest::getVar('tags', NULL, 'POST', 'array'); + if (count($tags)) + { + $tags = array_unique($tags); + foreach ($tags as $tag) + { + + $tag = JString::trim($tag); + if ($tag) + { + $tagID = false; + $K2Tag = JTable::getInstance('K2Tag', 'Table'); + $K2Tag->name = $tag; + // Tag has been filtred and does not exist + if ($K2Tag->check()) + { + $K2Tag->published = 1; + if ($K2Tag->store()) + { + $tagID = $K2Tag->id; + } + } + // Tag has been filtred and exists so try to find it's id + else if ($K2Tag->name) + { + $query = "SELECT id FROM #__k2_tags WHERE name=".$db->Quote($K2Tag->name); + $db->setQuery($query); + $tagID = $db->loadResult(); + } + if ($tagID) + { + $query = "INSERT INTO #__k2_tags_xref (`id`, `tagID`, `itemID`) VALUES (NULL, {intval($tagID)}, {intval($row->id)})"; + $db->setQuery($query); + $db->query(); + } + } + } + } + + } + else + { + $tags = JRequest::getVar('selectedTags', NULL, 'POST', 'array'); + if (count($tags)) + { + foreach ($tags as $tagID) + { + $query = "INSERT INTO #__k2_tags_xref (`id`, `tagID`, `itemID`) VALUES (NULL, {intval($tagID)}, {intval($row->id)})"; + $db->setQuery($query); + $db->query(); + } + } + + } + + if ($front && $row->published) + { + if (($isNew && !K2HelperPermissions::canPublishItem($row->catid)) || (!$isNew && !K2HelperPermissions::canEditPublished($row->catid))) + { + $row->published = 0; + $mainframe->enqueueMessage(JText::_('K2_YOU_DONT_HAVE_THE_PERMISSION_TO_PUBLISH_ITEMS'), 'notice'); + } + } + + $query = "UPDATE #__k2_items SET + video_caption = ".$db->Quote($row->video_caption).", + video_credits = ".$db->Quote($row->video_credits).", "; + + if (!is_null($row->video)) + { + $query .= " video = ".$db->Quote($row->video).", "; + } + if (!is_null($row->gallery)) + { + $query .= " gallery = ".$db->Quote($row->gallery).", "; + } + $query .= " extra_fields = ".$db->Quote($row->extra_fields).", + extra_fields_search = ".$db->Quote($row->extra_fields_search)." , + published = ".$db->Quote($row->published)." + WHERE id = ".$row->id; + $db->setQuery($query); + + if (!$db->query()) + { + $mainframe->redirect('index.php?option=com_k2&view=items', $db->getErrorMsg(), 'error'); + } + + $row->checkin(); + + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + + $dispatcher->trigger('onAfterK2Save', array( + &$row, + $isNew + )); + JPluginHelper::importPlugin('content'); + if (K2_JVERSION != '15') + { + $dispatcher->trigger('onContentAfterSave', array( + 'com_k2.item', + &$row, + $isNew + )); + } + else + { + $dispatcher->trigger('onAfterContentSave', array( + &$row, + $isNew + )); + } + + //Trigger the finder after save event + $dispatcher = JDispatcher::getInstance(); + JPluginHelper::importPlugin('finder'); + $results = $dispatcher->trigger('onFinderAfterSave', array( + 'com_k2.item', + $row, + $isNew + )); + + switch (JRequest::getCmd('task')) + { + case 'apply' : + $msg = JText::_('K2_CHANGES_TO_ITEM_SAVED'); + $link = 'index.php?option=com_k2&view=item&cid='.$row->id; + break; + case 'saveAndNew' : + $msg = JText::_('K2_ITEM_SAVED'); + $link = 'index.php?option=com_k2&view=item'; + break; + case 'save' : + default : + $msg = JText::_('K2_ITEM_SAVED'); + if ($front) + $link = 'index.php?option=com_k2&view=item&task=edit&cid='.$row->id.'&tmpl=component&Itemid='.JRequest::getInt('Itemid'); + else + $link = 'index.php?option=com_k2&view=items'; + break; + } + $mainframe->redirect($link, $msg); + } + + function cancel() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getInt('id'); + + if ($cid) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($cid); + $row->checkin(); + } + + $mainframe->redirect('index.php?option=com_k2&view=items'); + } + + function getVideoProviders() + { + + if (K2_JVERSION != '15') + { + $file = JPATH_PLUGINS.DS.'content'.DS.'jw_allvideos'.DS.'jw_allvideos'.DS.'includes'.DS.'sources.php'; + } + else + { + $file = JPATH_PLUGINS.DS.'content'.DS.'jw_allvideos'.DS.'includes'.DS.'sources.php'; + } + + jimport('joomla.filesystem.file'); + if (JFile::exists($file)) + { + require $file; + $thirdPartyProviders = array_slice($tagReplace, 40); + $providersTmp = array_keys($thirdPartyProviders); + $providers = array(); + foreach ($providersTmp as $providerTmp) + { + + if (stristr($providerTmp, 'google|google.co.uk|google.com.au|google.de|google.es|google.fr|google.it|google.nl|google.pl') !== false) + { + $provider = 'google'; + } + elseif (stristr($providerTmp, 'spike|ifilm') !== false) + { + $provider = 'spike'; + } + else + { + $provider = $providerTmp; + } + $providers[] = $provider; + } + return $providers; + } + else + { + return array(); + } + + } + + function download() + { + + $mainframe = JFactory::getApplication(); + $user = JFactory::getUser(); + jimport('joomla.filesystem.file'); + $params = JComponentHelper::getParams('com_k2'); + $id = JRequest::getInt('id'); + + JPluginHelper::importPlugin('k2'); + $dispatcher = JDispatcher::getInstance(); + + $attachment = JTable::getInstance('K2Attachment', 'Table'); + if ($mainframe->isSite()) + { + $token = JRequest::getVar('id'); + $check = JString::substr($token, JString::strpos($token, '_') + 1); + $hash = version_compare(JVERSION, '3.0', 'ge') ? JApplication::getHash($id) : JUtility::getHash($id); + if ($check != $hash) + { + JError::raiseError(404, JText::_('K2_NOT_FOUND')); + } + } + $attachment->load($id); + + // For front-end ensure that user has access to the item + if ($mainframe->isSite()) + { + $item = JTable::getInstance('K2Item', 'Table'); + $item->load($attachment->itemID); + $category = JTable::getInstance('K2Category', 'Table'); + $category->load($item->catid); + if (!$item->id || !$category->id) + { + JError::raiseError(404, JText::_('K2_NOT_FOUND')); + } + + if (K2_JVERSION == '15' && ($item->access > $user->get('aid', 0) || $category->access > $user->get('aid', 0))) + { + JError::raiseError(403, JText::_('K2_ALERTNOTAUTH')); + } + + if (K2_JVERSION != '15' && (!in_array($category->access, $user->getAuthorisedViewLevels()) || !in_array($item->access, $user->getAuthorisedViewLevels()))) + { + JError::raiseError(403, JText::_('K2_ALERTNOTAUTH')); + } + + } + + $dispatcher->trigger('onK2BeforeDownload', array( + &$attachment, + &$params + )); + + $path = $params->get('attachmentsFolder', NULL); + if (is_null($path)) + { + $savepath = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'attachments'; + } + else + { + $savepath = $path; + } + $file = $savepath.DS.$attachment->filename; + + if (JFile::exists($file)) + { + require_once (JPATH_COMPONENT_ADMINISTRATOR.DS.'lib'.DS.'class.upload.php'); + $handle = new Upload($file); + $dispatcher->trigger('onK2AfterDownload', array( + &$attachment, + &$params + )); + if ($mainframe->isSite()) + { + $attachment->hit(); + } + $len = filesize($file); + $filename = basename($file); + ob_end_clean(); + JResponse::clearHeaders(); + JResponse::setHeader('Pragma', 'public', true); + JResponse::setHeader('Expires', '0', true); + JResponse::setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true); + JResponse::setHeader('Content-Type', $handle->file_src_mime, true); + JResponse::setHeader('Content-Disposition', 'attachment; filename='.$filename.';', true); + JResponse::setHeader('Content-Transfer-Encoding', 'binary', true); + JResponse::setHeader('Content-Length', $len, true); + JResponse::sendHeaders(); + echo JFile::read($file); + + } + else + { + echo JText::_('K2_FILE_DOES_NOT_EXIST'); + } + $mainframe->close(); + } + + function getAttachments($itemID) + { + + $db = JFactory::getDBO(); + $query = "SELECT * FROM #__k2_attachments WHERE itemID=".(int)$itemID; + $db->setQuery($query); + $rows = $db->loadObjectList(); + foreach ($rows as $row) + { + $hash = version_compare(JVERSION, '3.0', 'ge') ? JApplication::getHash($row->id) : JUtility::getHash($row->id); + $row->link = JRoute::_('index.php?option=com_k2&view=item&task=download&id='.$row->id.'_'.$hash); + } + return $rows; + + } + + function deleteAttachment() + { + + $mainframe = JFactory::getApplication(); + $params = JComponentHelper::getParams('com_k2'); + jimport('joomla.filesystem.file'); + $id = JRequest::getInt('id'); + $itemID = JRequest::getInt('cid'); + + $db = JFactory::getDBO(); + $query = "SELECT COUNT(*) FROM #__k2_attachments WHERE itemID={$itemID} AND id={$id}"; + $db->setQuery($query); + $result = $db->loadResult(); + + if (!$result) + { + $mainframe->close(); + } + + $row = JTable::getInstance('K2Attachment', 'Table'); + $row->load($id); + + $path = $params->get('attachmentsFolder', NULL); + if (is_null($path)) + { + $savepath = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'attachments'; + } + else + { + $savepath = $path; + } + + if (JFile::exists($savepath.DS.$row->filename)) + { + JFile::delete($savepath.DS.$row->filename); + } + + $row->delete($id); + $mainframe->close(); + } + + function getAvailableTags($itemID = NULL) + { + + $db = JFactory::getDBO(); + $query = "SELECT * FROM #__k2_tags as tags"; + if (!is_null($itemID)) + $query .= " WHERE tags.id NOT IN (SELECT tagID FROM #__k2_tags_xref WHERE itemID=".(int)$itemID.")"; + $db->setQuery($query); + $rows = $db->loadObjectList(); + return $rows; + } + + function getCurrentTags($itemID) + { + + $db = JFactory::getDBO(); + $itemID = (int)$itemID; + $query = "SELECT tags.* + FROM #__k2_tags AS tags + JOIN #__k2_tags_xref AS xref ON tags.id = xref.tagID + WHERE xref.itemID = ".(int)$itemID." ORDER BY xref.id ASC"; + $db->setQuery($query); + $rows = $db->loadObjectList(); + return $rows; + } + + function resetHits() + { + $mainframe = JFactory::getApplication(); + $id = JRequest::getInt('id'); + $db = JFactory::getDBO(); + $query = "UPDATE #__k2_items SET hits=0 WHERE id={$id}"; + $db->setQuery($query); + $db->query(); + if ($mainframe->isAdmin()) + $url = 'index.php?option=com_k2&view=item&cid='.$id; + else + $url = 'index.php?option=com_k2&view=item&task=edit&cid='.$id.'&tmpl=component'; + $mainframe->redirect($url, JText::_('K2_SUCCESSFULLY_RESET_ITEM_HITS')); + } + + function resetRating() + { + $mainframe = JFactory::getApplication(); + $id = JRequest::getInt('id'); + $db = JFactory::getDBO(); + $query = "DELETE FROM #__k2_rating WHERE itemID={$id}"; + $db->setQuery($query); + $db->query(); + if ($mainframe->isAdmin()) + $url = 'index.php?option=com_k2&view=item&cid='.$id; + else + $url = 'index.php?option=com_k2&view=item&task=edit&cid='.$id.'&tmpl=component'; + $mainframe->redirect($url, JText::_('K2_SUCCESSFULLY_RESET_ITEM_RATING')); + } + + function getRating() + { + $id = JRequest::getInt('cid'); + $db = JFactory::getDBO(); + $query = "SELECT * FROM #__k2_rating WHERE itemID={$id}"; + $db->setQuery($query, 0, 1); + $row = $db->loadObject(); + return $row; + } + + function checkSIG() + { + $mainframe = JFactory::getApplication(); + if (K2_JVERSION != '15') + { + $check = JPATH_PLUGINS.DS.'content'.DS.'jw_sigpro'.DS.'jw_sigpro.php'; + } + else + { + $check = JPATH_PLUGINS.DS.'content'.DS.'jw_sigpro.php'; + } + if (JFile::exists($check)) + { + return true; + } + else + { + return false; + } + } + + function checkAllVideos() + { + $mainframe = JFactory::getApplication(); + if (K2_JVERSION != '15') + { + $check = JPATH_PLUGINS.DS.'content'.DS.'jw_allvideos'.DS.'jw_allvideos.php'; + } + else + { + $check = JPATH_PLUGINS.DS.'content'.DS.'jw_allvideos.php'; + } + if (JFile::exists($check)) + { + return true; + } + else + { + return false; + } + } + + function cleanText($text) + { + if (version_compare(JVERSION, '2.5.0', 'ge')) + { + $text = JComponentHelper::filterText($text); + } + else if (version_compare(JVERSION, '2.5.0', 'lt') && version_compare(JVERSION, '1.6.0', 'ge')) + { + JLoader::register('ContentHelper', JPATH_ADMINISTRATOR.DS.'components'.DS.'com_content'.DS.'helpers'.DS.'content.php'); + $text = ContentHelper::filterText($text); + } + else + { + $config = JComponentHelper::getParams('com_content'); + $user = JFactory::getUser(); + $gid = $user->get('gid'); + $filterGroups = $config->get('filter_groups'); + + // convert to array if one group selected + if ((!is_array($filterGroups) && (int)$filterGroups > 0)) + { + $filterGroups = array($filterGroups); + } + + if (is_array($filterGroups) && in_array($gid, $filterGroups)) + { + $filterType = $config->get('filter_type'); + $filterTags = preg_split('#[,\s]+#', trim($config->get('filter_tags'))); + $filterAttrs = preg_split('#[,\s]+#', trim($config->get('filter_attritbutes'))); + switch ($filterType) + { + case 'NH' : + $filter = new JFilterInput(); + break; + case 'WL' : + $filter = new JFilterInput($filterTags, $filterAttrs, 0, 0, 0); + break; + case 'BL' : + default : + $filter = new JFilterInput($filterTags, $filterAttrs, 1, 1); + break; + } + $text = $filter->clean($text); + } + elseif (empty($filterGroups) && $gid != '25') + { + // no default filtering for super admin (gid=25) + $filter = new JFilterInput( array(), array(), 1, 1); + $text = $filter->clean($text); + } + } + + return $text; + + } + +} diff --git a/administrator/components/com_k2/models/item.xml b/administrator/components/com_k2/models/item.xml new file mode 100644 index 0000000..1c7a33f --- /dev/null +++ b/administrator/components/com_k2/models/item.xml @@ -0,0 +1,778 @@ + +
    + K2_ITEM_EDIT_FORM + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    diff --git a/administrator/components/com_k2/models/items.php b/administrator/components/com_k2/models/items.php new file mode 100644 index 0000000..6f7ad07 --- /dev/null +++ b/administrator/components/com_k2/models/items.php @@ -0,0 +1,1339 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', 'i.id', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', 'DESC', 'word'); + $filter_trash = $mainframe->getUserStateFromRequest($option.$view.'filter_trash', 'filter_trash', 0, 'int'); + $filter_featured = $mainframe->getUserStateFromRequest($option.$view.'filter_featured', 'filter_featured', -1, 'int'); + $filter_category = $mainframe->getUserStateFromRequest($option.$view.'filter_category', 'filter_category', 0, 'int'); + $filter_author = $mainframe->getUserStateFromRequest($option.$view.'filter_author', 'filter_author', 0, 'int'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', -1, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + $tag = $mainframe->getUserStateFromRequest($option.$view.'tag', 'tag', 0, 'int'); + $language = $mainframe->getUserStateFromRequest($option.$view.'language', 'language', '', 'string'); + + $query = "SELECT i.*, g.name AS groupname, c.name AS category, v.name AS author, w.name as moderator, u.name AS editor FROM #__k2_items as i"; + + $query .= " LEFT JOIN #__k2_categories AS c ON c.id = i.catid"." LEFT JOIN #__groups AS g ON g.id = i.access"." LEFT JOIN #__users AS u ON u.id = i.checked_out"." LEFT JOIN #__users AS v ON v.id = i.created_by"." LEFT JOIN #__users AS w ON w.id = i.modified_by"; + + if ($params->get('showTagFilter') && $tag) + { + $query .= " LEFT JOIN #__k2_tags_xref AS tags_xref ON tags_xref.itemID = i.id"; + } + + $query .= " WHERE i.trash={$filter_trash}"; + + if ($search) + { + + $search = JString::str_ireplace('*', '', $search); + $words = explode(' ', $search); + for ($i = 0; $i < count($words); $i++) + { + $words[$i] = '+'.$words[$i]; + $words[$i] .= '*'; + } + $search = implode(' ', $words); + $escaped = K2_JVERSION == '15' ? $db->getEscaped($search, true) : $db->escape($search, true); + $search = $db->Quote($escaped, false); + + if ($params->get('adminSearch') == 'full') + $query .= " AND MATCH(i.title, i.introtext, i.`fulltext`, i.extra_fields_search, i.image_caption,i.image_credits,i.video_caption,i.video_credits,i.metadesc,i.metakey)"; + else + $query .= " AND MATCH( i.title )"; + + $query .= " AGAINST ({$search} IN BOOLEAN MODE)"; + } + + if ($filter_state > -1) + { + $query .= " AND i.published={$filter_state}"; + } + + if ($filter_featured > -1) + { + $query .= " AND i.featured={$filter_featured}"; + } + + if ($filter_category > 0) + { + if ($params->get('showChildCatItems')) + { + K2Model::addIncludePath(JPATH_SITE.DS.'components'.DS.'com_k2'.DS.'models'); + $itemListModel = K2Model::getInstance('Itemlist', 'K2Model'); + $categories = $itemListModel->getCategoryTree($filter_category); + $sql = @implode(',', $categories); + $query .= " AND i.catid IN ({$sql})"; + } + else + { + $query .= " AND i.catid={$filter_category}"; + } + + } + + if ($filter_author > 0) + { + $query .= " AND i.created_by={$filter_author}"; + } + + if ($params->get('showTagFilter') && $tag) + { + $query .= " AND tags_xref.tagID = {$tag}"; + } + + if ($language) + { + $query .= " AND (i.language = ".$db->Quote($language)." OR i.language = '*')"; + } + + if ($filter_order == 'i.ordering') + { + $query .= " ORDER BY i.catid, i.ordering {$filter_order_Dir}"; + } + else + { + $query .= " ORDER BY {$filter_order} {$filter_order_Dir} "; + } + + if (K2_JVERSION != '15') + { + $query = JString::str_ireplace('#__groups', '#__viewlevels', $query); + $query = JString::str_ireplace('g.name', 'g.title', $query); + } + $dispatcher = JDispatcher::getInstance(); + JPluginHelper::importPlugin('k2'); + $dispatcher->trigger('onK2BeforeSetQuery', array(&$query)); + $db->setQuery($query, $limitstart, $limit); + $rows = $db->loadObjectList(); + return $rows; + + } + + function getTotal() + { + + $mainframe = JFactory::getApplication(); + $params = JComponentHelper::getParams('com_k2'); + $option = JRequest::getCmd('option'); + $view = JRequest::getCmd('view'); + $db = JFactory::getDBO(); + $filter_trash = $mainframe->getUserStateFromRequest($option.$view.'filter_trash', 'filter_trash', 0, 'int'); + $filter_featured = $mainframe->getUserStateFromRequest($option.$view.'filter_featured', 'filter_featured', -1, 'int'); + $filter_category = $mainframe->getUserStateFromRequest($option.$view.'filter_category', 'filter_category', 0, 'int'); + $filter_author = $mainframe->getUserStateFromRequest($option.$view.'filter_author', 'filter_author', 0, 'int'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', -1, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + $tag = $mainframe->getUserStateFromRequest($option.$view.'tag', 'tag', 0, 'int'); + $language = $mainframe->getUserStateFromRequest($option.$view.'language', 'language', '', 'string'); + + $query = "SELECT COUNT(*) FROM #__k2_items AS i "; + + if ($params->get('showTagFilter') && $tag) + { + $query .= " LEFT JOIN #__k2_tags_xref AS tags_xref ON tags_xref.itemID = i.id"; + } + + $query .= " WHERE trash={$filter_trash} "; + + if ($search) + { + + $search = JString::str_ireplace('*', '', $search); + $words = explode(' ', $search); + for ($i = 0; $i < count($words); $i++) + { + $words[$i] = '+'.$words[$i]; + $words[$i] .= '*'; + } + $search = implode(' ', $words); + $escaped = K2_JVERSION == '15' ? $db->getEscaped($search, true) : $db->escape($search, true); + $search = $db->Quote($escaped, false); + + if ($params->get('adminSearch') == 'full') + $query .= " AND MATCH(title, introtext, `fulltext`, extra_fields_search, image_caption, image_credits, video_caption, video_credits, metadesc, metakey)"; + else + $query .= " AND MATCH( title )"; + + $query .= " AGAINST ({$search} IN BOOLEAN MODE)"; + } + + if ($filter_state > -1) + { + $query .= " AND published={$filter_state}"; + } + + if ($filter_featured > -1) + { + $query .= " AND featured={$filter_featured}"; + } + + if ($filter_category > 0) + { + if ($params->get('showChildCatItems')) + { + K2Model::addIncludePath(JPATH_SITE.DS.'components'.DS.'com_k2'.DS.'models'); + $itemListModel = K2Model::getInstance('Itemlist', 'K2Model'); + $categories = $itemListModel->getCategoryTree($filter_category); + $sql = @implode(',', $categories); + $query .= " AND catid IN ({$sql})"; + } + else + { + $query .= " AND catid={$filter_category}"; + } + + } + + if ($filter_author > 0) + { + $query .= " AND created_by={$filter_author}"; + } + + if ($params->get('showTagFilter') && $tag) + { + $query .= " AND tags_xref.tagID = {$tag}"; + } + + if ($language) + { + $query .= " AND (language = ".$db->Quote($language)." OR language = '*')"; + } + $dispatcher = JDispatcher::getInstance(); + JPluginHelper::importPlugin('k2'); + $dispatcher->trigger('onK2BeforeSetQuery', array(&$query)); + $db->setQuery($query); + $result = $db->loadResult(); + return $result; + + } + + function publish() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($id); + $row->publish($id, 1); + } + JPluginHelper::importPlugin('finder'); + $dispatcher = JDispatcher::getInstance(); + $dispatcher->trigger('onFinderChangeState', array('com_k2.item', $cid, 1)); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=items'); + } + + function unpublish() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($id); + $row->publish($id, 0); + } + JPluginHelper::importPlugin('finder'); + $dispatcher = JDispatcher::getInstance(); + $dispatcher->trigger('onFinderChangeState', array('com_k2.item', $cid, 0)); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=items'); + } + + function saveorder() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid', array(0), 'post', 'array'); + $total = count($cid); + $order = JRequest::getVar('order', array(0), 'post', 'array'); + JArrayHelper::toInteger($order, array(0)); + $groupings = array(); + for ($i = 0; $i < $total; $i++) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->load((int)$cid[$i]); + $groupings[] = $row->catid; + if ($row->ordering != $order[$i]) + { + $row->ordering = $order[$i]; + if (!$row->store()) + { + JError::raiseError(500, $db->getErrorMsg()); + } + } + } + $params = JComponentHelper::getParams('com_k2'); + if (!$params->get('disableCompactOrdering')) + { + $groupings = array_unique($groupings); + foreach ($groupings as $group) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->reorder('catid = '.(int)$group.' AND trash=0'); + } + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + return true; + } + + function orderup() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($cid[0]); + $row->move(-1, 'catid = '.(int)$row->catid.' AND trash=0'); + $params = JComponentHelper::getParams('com_k2'); + if (!$params->get('disableCompactOrdering')) + $row->reorder('catid = '.(int)$row->catid.' AND trash=0'); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ORDERING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=items', $msg); + } + + function orderdown() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($cid[0]); + $row->move(1, 'catid = '.(int)$row->catid.' AND trash=0'); + $params = JComponentHelper::getParams('com_k2'); + if (!$params->get('disableCompactOrdering')) + $row->reorder('catid = '.(int)$row->catid.' AND trash=0'); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ORDERING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=items', $msg); + } + + function savefeaturedorder() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid', array(0), 'post', 'array'); + $total = count($cid); + $order = JRequest::getVar('order', array(0), 'post', 'array'); + JArrayHelper::toInteger($order, array(0)); + $groupings = array(); + for ($i = 0; $i < $total; $i++) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->load((int)$cid[$i]); + $groupings[] = $row->catid; + if ($row->featured_ordering != $order[$i]) + { + $row->featured_ordering = $order[$i]; + if (!$row->store()) + { + JError::raiseError(500, $db->getErrorMsg()); + } + } + } + $params = JComponentHelper::getParams('com_k2'); + if (!$params->get('disableCompactOrdering')) + { + $groupings = array_unique($groupings); + foreach ($groupings as $group) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->reorder('featured = 1 AND trash=0', 'featured_ordering'); + } + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + return true; + } + + function featuredorderup() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($cid[0]); + $row->move(-1, 'featured=1 AND trash=0', 'featured_ordering'); + $params = JComponentHelper::getParams('com_k2'); + if (!$params->get('disableCompactOrdering')) + $row->reorder('featured=1 AND trash=0', 'featured_ordering'); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ORDERING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=items', $msg); + } + + function featuredorderdown() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($cid[0]); + $row->move(1, 'featured=1 AND trash=0', 'featured_ordering'); + $params = JComponentHelper::getParams('com_k2'); + if (!$params->get('disableCompactOrdering')) + $row->reorder('featured=1 AND trash=0', 'featured_ordering'); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ORDERING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=items', $msg); + } + + function accessregistered() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $row = JTable::getInstance('K2Item', 'Table'); + $cid = JRequest::getVar('cid'); + $row->load($cid[0]); + $row->access = 1; + if (!$row->check()) + { + return $row->getError(); + } + if (!$row->store()) + { + return $row->getError(); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ACCESS_SETTING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=items', $msg); + } + + function accessspecial() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $row = JTable::getInstance('K2Item', 'Table'); + $cid = JRequest::getVar('cid'); + $row->load($cid[0]); + $row->access = 2; + if (!$row->check()) + { + return $row->getError(); + } + if (!$row->store()) + { + return $row->getError(); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ACCESS_SETTING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=items', $msg); + } + + function accesspublic() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $row = JTable::getInstance('K2Item', 'Table'); + $cid = JRequest::getVar('cid'); + $row->load($cid[0]); + $row->access = 0; + if (!$row->check()) + { + return $row->getError(); + } + if (!$row->store()) + { + return $row->getError(); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $msg = JText::_('K2_NEW_ACCESS_SETTING_SAVED'); + $mainframe->redirect('index.php?option=com_k2&view=items', $msg); + } + + function copy() + { + + $mainframe = JFactory::getApplication(); + jimport('joomla.filesystem.file'); + jimport('joomla.filesystem.folder'); + $params = JComponentHelper::getParams('com_k2'); + $itemModel = K2Model::getInstance('Item', 'K2Model'); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + JArrayHelper::toInteger($cid); + $row = JTable::getInstance('K2Item', 'Table'); + + $nullDate = $db->getNullDate(); + + foreach ($cid as $id) + { + + //Load source item + $item = JTable::getInstance('K2Item', 'Table'); + $item->load($id); + $item->id = (int)$item->id; + + //Source images + $sourceImage = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'src'.DS.md5("Image".$item->id).'.jpg'; + $sourceImageXS = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$item->id).'_XS.jpg'; + $sourceImageS = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$item->id).'_S.jpg'; + $sourceImageM = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$item->id).'_M.jpg'; + $sourceImageL = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$item->id).'_L.jpg'; + $sourceImageXL = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$item->id).'_XL.jpg'; + $sourceImageGeneric = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$item->id).'_Generic.jpg'; + + //Source gallery + $sourceGallery = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'galleries'.DS.$item->id; + $sourceGalleryTag = $item->gallery; + + //Source video + preg_match_all("#^{(.*?)}(.*?){#", $item->video, $matches, PREG_PATTERN_ORDER); + $videotype = $matches[1][0]; + $videofile = $matches[2][0]; + + if ($videotype == 'flv' || $videotype == 'swf' || $videotype == 'wmv' || $videotype == 'mov' || $videotype == 'mp4' || $videotype == '3gp' || $videotype == 'divx') + { + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'videos'.DS.$videofile.'.'.$videotype)) + { + $sourceVideo = $videofile.'.'.$videotype; + //$row->video='{'.$videotype.'}'.$row->id.'{/'.$videotype.'}'; + } + } + + //Source tags + $query = "SELECT * FROM #__k2_tags_xref WHERE itemID={$item->id}"; + $db->setQuery($query); + $sourceTags = $db->loadObjectList(); + + //Source Attachments + $sourceAttachments = $itemModel->getAttachments($item->id); + + //Save target item + $row = JTable::getInstance('K2Item', 'Table'); + $row = $item; + $row->id = NULL; + $row->title = JText::_('K2_COPY_OF').' '.$item->title; + $row->hits = 0; + $row->published = 0; + $datenow = JFactory::getDate(); + $row->created = K2_JVERSION == '15' ? $datenow->toMySQL() : $datenow->toSql(); + $row->modified = $nullDate; + $row->store(); + + //Target images + if (JFile::exists($sourceImage)) + JFile::copy($sourceImage, JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'src'.DS.md5("Image".$row->id).'.jpg'); + if (JFile::exists($sourceImageXS)) + JFile::copy($sourceImageXS, JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_XS.jpg'); + if (JFile::exists($sourceImageS)) + JFile::copy($sourceImageS, JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_S.jpg'); + if (JFile::exists($sourceImageM)) + JFile::copy($sourceImageM, JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_M.jpg'); + if (JFile::exists($sourceImageL)) + JFile::copy($sourceImageL, JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_L.jpg'); + if (JFile::exists($sourceImageXL)) + JFile::copy($sourceImageXL, JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_XL.jpg'); + if (JFile::exists($sourceImageGeneric)) + JFile::copy($sourceImageGeneric, JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_Generic.jpg'); + + //Target gallery + if ($sourceGalleryTag) + { + if (JString::strpos($sourceGalleryTag, 'http://')) + { + $row->gallery = $sourceGalleryTag; + } + else + { + $row->gallery = '{gallery}'.$row->id.'{/gallery}'; + if (JFolder::exists($sourceGallery)) + { + JFolder::copy($sourceGallery, JPATH_ROOT.DS.'media'.DS.'k2'.DS.'galleries'.DS.$row->id); + } + } + } + + //Target video + if (isset($sourceVideo) && JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'videos'.DS.$sourceVideo)) + { + JFile::copy(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'videos'.DS.$sourceVideo, JPATH_ROOT.DS.'media'.DS.'k2'.DS.'videos'.DS.$row->id.'.'.$videotype); + $row->video = '{'.$videotype.'}'.$row->id.'{/'.$videotype.'}'; + } + + //Target attachments + $path = $params->get('attachmentsFolder', NULL); + if (is_null($path)) + $savepath = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'attachments'; + else + $savepath = $path; + + foreach ($sourceAttachments as $attachment) + { + if (JFile::exists($savepath.DS.$attachment->filename)) + { + JFile::copy($savepath.DS.$attachment->filename, $savepath.DS.$row->id.'_'.$attachment->filename); + $attachmentRow = JTable::getInstance('K2Attachment', 'Table'); + $attachmentRow->itemID = $row->id; + $attachmentRow->title = $attachment->title; + $attachmentRow->titleAttribute = $attachment->titleAttribute; + $attachmentRow->filename = $row->id.'_'.$attachment->filename; + $attachmentRow->hits = 0; + $attachmentRow->store(); + } + } + + //Target tags + foreach ($sourceTags as $tag) + { + $query = "INSERT INTO #__k2_tags_xref (`id`, `tagID`, `itemID`) VALUES (NULL, {intval($tag->tagID)}, {intval($row->id)})"; + $db->setQuery($query); + $db->query(); + } + + $row->store(); + } + + $mainframe->redirect('index.php?option=com_k2&view=items', JText::_('K2_COPY_COMPLETED')); + } + + function featured() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($id); + if ($row->featured == 1) + $row->featured = 0; + else + { + $row->featured = 1; + $row->featured_ordering = 1; + } + $row->store(); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=items', JText::_('K2_ITEMS_CHANGED')); + } + + function trash() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + JArrayHelper::toInteger($cid); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($id); + $row->trash = 1; + $row->store(); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=items', JText::_('K2_ITEMS_MOVED_TO_TRASH')); + + } + + function restore() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + $warning = false; + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($id); + $query = "SELECT COUNT(*) FROM #__k2_categories WHERE id=".(int)$row->catid." AND trash = 0"; + $db->setQuery($query); + $result = $db->loadResult(); + if ($result) + { + $row->trash = 0; + $row->store(); + } + else + { + $warning = true; + } + + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + if ($warning) + $mainframe->enqueueMessage(JText::_('K2_SOME_OF_THE_ITEMS_HAVE_NOT_BEEN_RESTORED_BECAUSE_THEY_BELONG_TO_A_CATEGORY_WHICH_IS_IN_TRASH'), 'notice'); + $mainframe->redirect('index.php?option=com_k2&view=items', JText::_('K2_ITEMS_RESTORED')); + + } + + function remove() + { + jimport('joomla.filesystem.file'); + jimport('joomla.filesystem.folder'); + $mainframe = JFactory::getApplication(); + $params = JComponentHelper::getParams('com_k2'); + $itemModel = K2Model::getInstance('Item', 'K2Model'); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + JPluginHelper::importPlugin('finder'); + $dispatcher = JDispatcher::getInstance(); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($id); + $row->id = (int)$row->id; + //Delete images + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'src'.DS.md5("Image".$row->id).'.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'src'.DS.md5("Image".$row->id).'.jpg'); + } + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_XS.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_XS.jpg'); + } + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_S.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_S.jpg'); + } + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_M.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_M.jpg'); + } + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_L.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_L.jpg'); + } + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_XL.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_XL.jpg'); + } + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_Generic.jpg')) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$row->id).'_Generic.jpg'); + } + + //Delete gallery + if (JFolder::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'galleries'.DS.$row->id)) + JFolder::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'galleries'.DS.$row->id); + + //Delete video + preg_match_all("#^{(.*?)}(.*?){#", $row->video, $matches, PREG_PATTERN_ORDER); + $videotype = $matches[1][0]; + $videofile = $matches[2][0]; + + $videoExtensions = array('flv', 'mp4', 'ogv', 'webm', 'f4v', 'm4v', '3gp', '3g2', 'mov', 'mpeg', 'mpg', 'avi', 'wmv', 'divx', 'swf'); + $audioExtensions = array('mp3', 'aac', 'mp4', 'ogg', 'wma'); + + if (in_array($videotype, $videoExtensions) || in_array($videotype, $audioExtensions)) + { + + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'videos'.DS.$videofile.'.'.$videotype)) + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'videos'.DS.$videofile.'.'.$videotype); + + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'audio'.DS.$videofile.'.'.$videotype)) + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'audio'.DS.$videofile.'.'.$videotype); + } + + //Delete attachments + $path = $params->get('attachmentsFolder', NULL); + if (is_null($path)) + $savepath = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'attachments'; + else + $savepath = $path; + + $attachments = $itemModel->getAttachments($row->id); + + foreach ($attachments as $attachment) + { + if (JFile::exists($savepath.DS.$attachment->filename)) + JFile::delete($savepath.DS.$attachment->filename); + } + + $query = "DELETE FROM #__k2_attachments WHERE itemID={$row->id}"; + $db->setQuery($query); + $db->query(); + + //Delete tags + $query = "DELETE FROM #__k2_tags_xref WHERE itemID={$row->id}"; + $db->setQuery($query); + $db->query(); + + //Delete comments + $query = "DELETE FROM #__k2_comments WHERE itemID={$row->id}"; + $db->setQuery($query); + $db->query(); + + $row->delete($id); + + $dispatcher->trigger('onFinderAfterDelete', array('com_k2.item', $row)); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=items', JText::_('K2_DELETE_COMPLETED')); + } + + function import() + { + + $mainframe = JFactory::getApplication(); + jimport('joomla.filesystem.file'); + $db = JFactory::getDBO(); + $query = "SELECT * FROM #__sections"; + $db->setQuery($query); + $sections = $db->loadObjectList(); + + $query = "SELECT COUNT(*) FROM #__k2_items"; + $db->setQuery($query); + $result = $db->loadResult(); + if ($result) + $preserveItemIDs = false; + else + $preserveItemIDs = true; + + $xml = new JSimpleXML; + $xml->loadFile(JPATH_COMPONENT.DS.'models'.DS.'category.xml'); + $categoryParams = class_exists('JParameter') ? new JParameter('') : new JRegistry(''); + + foreach ($xml->document->params as $paramGroup) + { + foreach ($paramGroup->param as $param) + { + if ($param->attributes('type') != 'spacer' && $param->attributes('name')) + { + $categoryParams->set($param->attributes('name'), $param->attributes('default')); + } + } + } + $categoryParams = $categoryParams->toString(); + + $xml = new JSimpleXML; + $xml->loadFile(JPATH_COMPONENT.DS.'models'.DS.'item.xml'); + $itemParams = class_exists('JParameter') ? new JParameter('') : new JRegistry(''); + + foreach ($xml->document->params as $paramGroup) + { + foreach ($paramGroup->param as $param) + { + if ($param->attributes('type') != 'spacer' && $param->attributes('name')) + { + $itemParams->set($param->attributes('name'), $param->attributes('default')); + } + } + } + $itemParams = $itemParams->toString(); + + $query = "SELECT id, name FROM #__k2_tags"; + $db->setQuery($query); + $tags = $db->loadObjectList(); + + if (is_null($tags)) + $tags = array(); + + foreach ($sections as $section) + { + $K2Category = JTable::getInstance('K2Category', 'Table'); + $K2Category->name = $section->title; + $K2Category->alias = $section->title; + $K2Category->description = $section->description; + $K2Category->parent = 0; + $K2Category->published = $section->published; + $K2Category->access = $section->access; + $K2Category->ordering = $section->ordering; + $K2Category->image = $section->image; + $K2Category->trash = 0; + $K2Category->params = $categoryParams; + $K2Category->check(); + $K2Category->store(); + if (JFile::exists(JPATH_SITE.DS.'images'.DS.'stories'.DS.$section->image)) + { + JFile::copy(JPATH_SITE.DS.'images'.DS.'stories'.DS.$section->image, JPATH_SITE.DS.'media'.DS.'k2'.DS.'categories'.DS.$K2Category->image); + } + $query = "SELECT * FROM #__categories WHERE section = ".(int)$section->id; + $db->setQuery($query); + $categories = $db->loadObjectList(); + + foreach ($categories as $category) + { + $K2Subcategory = JTable::getInstance('K2Category', 'Table'); + $K2Subcategory->name = $category->title; + $K2Subcategory->alias = $category->title; + $K2Subcategory->description = $category->description; + $K2Subcategory->parent = $K2Category->id; + $K2Subcategory->published = $category->published; + $K2Subcategory->access = $category->access; + $K2Subcategory->ordering = $category->ordering; + $K2Subcategory->image = $category->image; + $K2Subcategory->trash = 0; + $K2Subcategory->params = $categoryParams; + $K2Subcategory->check(); + $K2Subcategory->store(); + if (JFile::exists(JPATH_SITE.DS.'images'.DS.'stories'.DS.$category->image)) + { + JFile::copy(JPATH_SITE.DS.'images'.DS.'stories'.DS.$category->image, JPATH_SITE.DS.'media'.DS.'k2'.DS.'categories'.DS.$K2Subcategory->image); + } + + $query = "SELECT article.*, xref.content_id + FROM #__content AS article + LEFT JOIN #__content_frontpage AS xref ON article.id = xref.content_id + WHERE catid = ".(int)$category->id; + $db->setQuery($query); + $items = $db->loadObjectList(); + + foreach ($items as $item) + { + + $K2Item = JTable::getInstance('K2Item', 'Table'); + $K2Item->title = $item->title; + $K2Item->alias = $item->title; + $K2Item->catid = $K2Subcategory->id; + if ($item->state < 0) + { + $K2Item->trash = 1; + } + else + { + $K2Item->trash = 0; + $K2Item->published = $item->state; + } + $K2Item->featured = ($item->content_id) ? 1 : 0; + $K2Item->introtext = $item->introtext; + $K2Item->fulltext = $item->fulltext; + $K2Item->created = $item->created; + $K2Item->created_by = $item->created_by; + $K2Item->created_by_alias = $item->created_by_alias; + $K2Item->modified = $item->modified; + $K2Item->modified_by = $item->modified_by; + $K2Item->publish_up = $item->publish_up; + $K2Item->publish_down = $item->publish_down; + $K2Item->access = $item->access; + $K2Item->ordering = $item->ordering; + $K2Item->hits = $item->hits; + $K2Item->metadesc = $item->metadesc; + $K2Item->metadata = $item->metadata; + $K2Item->metakey = $item->metakey; + $K2Item->params = $itemParams; + $K2Item->check(); + if ($preserveItemIDs) + { + $K2Item->id = $item->id; + $db->insertObject('#__k2_items', $K2Item); + } + else + { + $K2Item->store(); + } + + if (!empty($item->metakey)) + { + $itemTags = explode(',', $item->metakey); + foreach ($itemTags as $itemTag) + { + $itemTag = JString::trim($itemTag); + if (in_array($itemTag, JArrayHelper::getColumn($tags, 'name'))) + { + + $query = "SELECT id FROM #__k2_tags WHERE name=".$db->Quote($itemTag); + $db->setQuery($query); + $id = $db->loadResult(); + $query = "INSERT INTO #__k2_tags_xref (`id`, `tagID`, `itemID`) VALUES (NULL, {$id}, {$K2Item->id})"; + $db->setQuery($query); + $db->query(); + } + else + { + $K2Tag = JTable::getInstance('K2Tag', 'Table'); + $K2Tag->name = $itemTag; + $K2Tag->published = 1; + $K2Tag->store(); + $tags[] = $K2Tag; + $query = "INSERT INTO #__k2_tags_xref (`id`, `tagID`, `itemID`) VALUES (NULL, {$K2Tag->id}, {$K2Item->id})"; + $db->setQuery($query); + $db->query(); + } + } + } + } + + } + + } + + // Handle uncategorized articles + $query = "SELECT * FROM #__content WHERE sectionid = 0"; + $db->setQuery($query); + $items = $db->loadObjectList(); + + if ($items) + { + $K2Uncategorised = JTable::getInstance('K2Category', 'Table'); + $K2Uncategorised->name = 'Uncategorized'; + $K2Uncategorised->alias = 'Uncategorized'; + $K2Uncategorised->parent = 0; + $K2Uncategorised->published = 1; + $K2Uncategorised->access = 0; + $K2Uncategorised->ordering = 0; + $K2Uncategorised->trash = 0; + $K2Uncategorised->params = $categoryParams; + $K2Uncategorised->check(); + $K2Uncategorised->store(); + + foreach ($items as $item) + { + + $K2Item = JTable::getInstance('K2Item', 'Table'); + $K2Item->title = $item->title; + $K2Item->alias = $item->title; + $K2Item->catid = $K2Uncategorised->id; + if ($item->state < 0) + { + $K2Item->trash = 1; + } + else + { + $K2Item->trash = 0; + $K2Item->published = $item->state; + } + $K2Item->introtext = $item->introtext; + $K2Item->fulltext = $item->fulltext; + $K2Item->created = $item->created; + $K2Item->created_by = $item->created_by; + $K2Item->created_by_alias = $item->created_by_alias; + $K2Item->modified = $item->modified; + $K2Item->modified_by = $item->modified_by; + $K2Item->publish_up = $item->publish_up; + $K2Item->publish_down = $item->publish_down; + $K2Item->access = $item->access; + $K2Item->ordering = $item->ordering; + $K2Item->hits = $item->hits; + $K2Item->metadesc = $item->metadesc; + $K2Item->metadata = $item->metadata; + $K2Item->metakey = $item->metakey; + $K2Item->params = $itemParams; + $K2Item->check(); + if ($preserveItemIDs) + { + $K2Item->id = $item->id; + $db->insertObject('#__k2_items', $K2Item); + } + else + { + $K2Item->store(); + } + + if (!empty($item->metakey)) + { + $itemTags = explode(',', $item->metakey); + foreach ($itemTags as $itemTag) + { + $itemTag = JString::trim($itemTag); + if (in_array($itemTag, JArrayHelper::getColumn($tags, 'name'))) + { + + $query = "SELECT id FROM #__k2_tags WHERE name=".$db->Quote($itemTag); + $db->setQuery($query); + $id = $db->loadResult(); + $query = "INSERT INTO #__k2_tags_xref (`id`, `tagID`, `itemID`) VALUES (NULL, {$id}, {$K2Item->id})"; + $db->setQuery($query); + $db->query(); + } + else + { + $K2Tag = JTable::getInstance('K2Tag', 'Table'); + $K2Tag->name = $itemTag; + $K2Tag->published = 1; + $K2Tag->store(); + $tags[] = $K2Tag; + $query = "INSERT INTO #__k2_tags_xref (`id`, `tagID`, `itemID`) VALUES (NULL, {$K2Tag->id}, {$K2Item->id})"; + $db->setQuery($query); + $db->query(); + } + } + } + } + } + $mainframe->redirect('index.php?option=com_k2&view=items', JText::_('K2_IMPORT_COMPLETED')); + } + + function importJ16() + { + + jimport('joomla.filesystem.file'); + jimport('joomla.html.parameter'); + jimport('joomla.utilities.xmlelement'); + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + + $query = "SELECT COUNT(*) FROM #__k2_categories"; + $db->setQuery($query); + $result = $db->loadResult(); + if ($result) + { + $preserveCategoryIDs = false; + } + else + { + $preserveCategoryIDs = true; + } + + $query = "SELECT COUNT(*) FROM #__k2_items"; + $db->setQuery($query); + $result = $db->loadResult(); + if ($result) + { + $preserveItemIDs = false; + } + else + { + $preserveItemIDs = true; + } + $xml = new JXMLElement(JFile::read(JPATH_COMPONENT.DS.'models'.DS.'category.xml')); + $categoryParams = class_exists('JParameter') ? new JParameter('') : new JRegistry(''); + foreach ($xml->params as $paramGroup) + { + foreach ($paramGroup->param as $param) + { + if ((string)$param->attributes()->type != 'spacer' && (string)$param->attributes()->name) + { + $categoryParams->set((string)$param->attributes()->name, (string)$param->attributes()->default); + } + } + } + $categoryParams = $categoryParams->toString(); + + $xml = new JXMLElement(JFile::read(JPATH_COMPONENT.DS.'models'.DS.'item.xml')); + $itemParams = class_exists('JParameter') ? new JParameter('') : new JRegistry(''); + foreach ($xml->params as $paramGroup) + { + foreach ($paramGroup->param as $param) + { + if ((string)$param->attributes()->type != 'spacer' && (string)$param->attributes()->name) + { + $itemParams->set((string)$param->attributes()->name, (string)$param->attributes()->default); + } + } + } + $itemParams = $itemParams->toString(); + + $query = "SELECT id, name FROM #__k2_tags"; + $db->setQuery($query); + $tags = $db->loadObjectList(); + + if (is_null($tags)) + $tags = array(); + + $query = "SELECT * FROM #__categories WHERE extension = 'com_content'"; + $db->setQuery($query); + $categories = $db->loadObjectList(); + $mapping = array(); + foreach ($categories as $category) + { + $category->params = json_decode($category->params); + $category->image = $category->params->image; + $K2Category = JTable::getInstance('K2Category', 'Table'); + $K2Category->name = $category->title; + $K2Category->alias = $category->title; + $K2Category->description = $category->description; + $K2Category->parent = $category->parent_id; + if ($K2Category->parent == 1) + { + $K2Category->parent = 0; + } + $K2Category->published = $category->published; + $K2Category->access = $category->access; + $K2Category->ordering = $K2Category->getNextOrder('parent='.(int)$category->parent_id); + $K2Category->image = basename($category->image); + $K2Category->trash = 0; + $K2Category->language = $category->language; + $K2Category->params = $categoryParams; + $K2Category->check(); + if ($preserveCategoryIDs) + { + $K2Category->id = $category->id; + $db->insertObject('#__k2_categories', $K2Category); + } + else + { + $K2Category->store(); + $mapping[$category->id] = $K2Category->id; + + } + + if ($K2Category->image && JFile::exists(realpath(JPATH_SITE.DS.$category->image))) + { + JFile::copy(realpath(JPATH_SITE.DS.$category->image), JPATH_SITE.DS.'media'.DS.'k2'.DS.'categories'.DS.$K2Category->image); + } + $query = "SELECT article.*, xref.content_id + FROM #__content AS article + LEFT JOIN #__content_frontpage AS xref ON article.id = xref.content_id + WHERE catid = ".(int)$category->id; + $db->setQuery($query); + $items = $db->loadObjectList(); + + foreach ($items as $item) + { + + $K2Item = JTable::getInstance('K2Item', 'Table'); + $K2Item->title = $item->title; + $K2Item->alias = $item->title; + $K2Item->catid = $K2Category->id; + if ($item->state < 0) + { + $K2Item->trash = 1; + } + else + { + $K2Item->trash = 0; + } + $K2Item->published = 1; + if ($item->state == 0) + { + $K2Item->published = 0; + } + $K2Item->featured = ($item->content_id) ? 1 : 0; + $K2Item->introtext = $item->introtext; + $K2Item->fulltext = $item->fulltext; + $K2Item->created = $item->created; + $K2Item->created_by = $item->created_by; + $K2Item->created_by_alias = $item->created_by_alias; + $K2Item->modified = $item->modified; + $K2Item->modified_by = $item->modified_by; + $K2Item->publish_up = $item->publish_up; + $K2Item->publish_down = $item->publish_down; + $K2Item->access = $item->access; + $K2Item->ordering = $item->ordering; + $K2Item->hits = $item->hits; + $K2Item->metadesc = $item->metadesc; + $K2Item->metadata = $item->metadata; + $K2Item->metakey = $item->metakey; + $K2Item->params = $itemParams; + $K2Item->language = $item->language; + $K2Item->check(); + if ($preserveItemIDs) + { + $K2Item->id = $item->id; + $db->insertObject('#__k2_items', $K2Item); + } + else + { + $K2Item->store(); + } + + if (!empty($item->metakey)) + { + $itemTags = explode(',', $item->metakey); + foreach ($itemTags as $itemTag) + { + $itemTag = JString::trim($itemTag); + if (in_array($itemTag, JArrayHelper::getColumn($tags, 'name'))) + { + + $query = "SELECT id FROM #__k2_tags WHERE name=".$db->Quote($itemTag); + $db->setQuery($query); + $id = $db->loadResult(); + $query = "INSERT INTO #__k2_tags_xref (`id`, `tagID`, `itemID`) VALUES (NULL, {$id}, {$K2Item->id})"; + $db->setQuery($query); + $db->query(); + } + else + { + $K2Tag = JTable::getInstance('K2Tag', 'Table'); + $K2Tag->name = $itemTag; + $K2Tag->published = 1; + $K2Tag->store(); + $tags[] = $K2Tag; + $query = "INSERT INTO #__k2_tags_xref (`id`, `tagID`, `itemID`) VALUES (NULL, {$K2Tag->id}, {$K2Item->id})"; + $db->setQuery($query); + $db->query(); + } + } + } + } + + } + + foreach ($mapping as $oldID => $newID) + { + $query = "UPDATE #__k2_categories SET parent=".$newID." WHERE parent=".$oldID; + $db->setQuery($query); + $db->query(); + } + + $mainframe->redirect('index.php?option=com_k2&view=items', JText::_('K2_IMPORT_COMPLETED')); + } + + function move() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + $catid = JRequest::getInt('category'); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($id); + $row->catid = $catid; + $row->ordering = $row->getNextOrder('catid = '.$row->catid.' AND published = 1'); + $row->store(); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=items', JText::_('K2_MOVE_COMPLETED')); + + } + + function getItemsAuthors() + { + $db = $this->getDBO(); + $query = "SELECT id, name, block FROM #__users WHERE id IN(SELECT DISTINCT(created_by) FROM #__k2_items) ORDER BY name"; + $db->setQuery($query); + $rows = $db->loadObjectList(); + return $rows; + } + +} diff --git a/administrator/components/com_k2/models/model.php b/administrator/components/com_k2/models/model.php new file mode 100644 index 0000000..5433e6b --- /dev/null +++ b/administrator/components/com_k2/models/model.php @@ -0,0 +1,49 @@ +loadByOption('com_k2'); + $post = JRequest::get('post'); + $component->bind($post); + if (!$component->check()) + { + $mainframe->enqueueMessage($component->getError(), 'error'); + return false; + } + if (!$component->store()) + { + $mainframe->enqueueMessage($component->getError(), 'error'); + return false; + } + return true; + } + + function & getParams() + { + static $instance; + if ($instance == null) + { + $component = JTable::getInstance('component'); + $component->loadByOption('com_k2'); + $instance = new JParameter($component->params, JPATH_ADMINISTRATOR.DS.'components'.DS.'com_k2'.DS.'config.xml'); + } + return $instance; + } + +} diff --git a/administrator/components/com_k2/models/tag.php b/administrator/components/com_k2/models/tag.php new file mode 100644 index 0000000..984e727 --- /dev/null +++ b/administrator/components/com_k2/models/tag.php @@ -0,0 +1,146 @@ +load($cid); + return $row; + } + + function save() + { + + $mainframe = JFactory::getApplication(); + $row = JTable::getInstance('K2Tag', 'Table'); + + if (!$row->bind(JRequest::get('post'))) + { + $mainframe->redirect('index.php?option=com_k2&view=tags', $row->getError(), 'error'); + } + + if (!$row->check()) + { + $mainframe->redirect('index.php?option=com_k2&view=tag&cid='.$row->id, $row->getError(), 'error'); + } + + if (!$row->store()) + { + $mainframe->redirect('index.php?option=com_k2&view=tags', $row->getError(), 'error'); + } + + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + + switch(JRequest::getCmd('task')) + { + case 'apply' : + $msg = JText::_('K2_CHANGES_TO_TAG_SAVED'); + $link = 'index.php?option=com_k2&view=tag&cid='.$row->id; + break; + case 'save' : + default : + $msg = JText::_('K2_TAG_SAVED'); + $link = 'index.php?option=com_k2&view=tags'; + break; + } + $mainframe->redirect($link, $msg); + } + + function addTag() + { + + $mainframe = JFactory::getApplication(); + + $user = JFactory::getUser(); + $params = JComponentHelper::getParams('com_k2'); + if ($user->gid < 24 && $params->get('lockTags')) + JError::raiseError(403, JText::_('K2_ALERTNOTAUTH')); + + $tag = JRequest::getString('tag'); + $tag = str_replace('-', '', $tag); + $tag = str_replace('.', '', $tag); + + $response = new JObject; + $response->set('name', $tag); + + require_once (JPATH_COMPONENT_ADMINISTRATOR.DS.'lib'.DS.'JSON.php'); + $json = new Services_JSON; + + if (empty($tag)) + { + $response->set('msg', JText::_('K2_YOU_NEED_TO_ENTER_A_TAG', true)); + echo $json->encode($response); + $mainframe->close(); + } + + $db = JFactory::getDBO(); + $query = "SELECT COUNT(*) FROM #__k2_tags WHERE name=".$db->Quote($tag); + $db->setQuery($query); + $result = $db->loadResult(); + + if ($result > 0) + { + $response->set('msg', JText::_('K2_TAG_ALREADY_EXISTS', true)); + echo $json->encode($response); + $mainframe->close(); + } + + $row = JTable::getInstance('K2Tag', 'Table'); + $row->name = $tag; + $row->published = 1; + $row->store(); + + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + + $response->set('id', $row->id); + $response->set('status', 'success'); + $response->set('msg', JText::_('K2_TAG_ADDED_TO_AVAILABLE_TAGS_LIST', true)); + echo $json->encode($response); + + $mainframe->close(); + + } + + function tags() + { + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $word = JRequest::getString('q', null); + if (K2_JVERSION == '15') + { + $word = $db->Quote($db->getEscaped($word, true).'%', false); + } + else + { + $word = $db->Quote($db->escape($word, true).'%', false); + } + $query = "SELECT name FROM #__k2_tags WHERE name LIKE ".$word; + $db->setQuery($query); + $result = K2_JVERSION == '30' ? $db->loadColumn() : $db->loadResultArray(); + require_once (JPATH_COMPONENT_ADMINISTRATOR.DS.'lib'.DS.'JSON.php'); + $json = new Services_JSON; + echo $json->encode($result); + $mainframe->close(); + } + +} diff --git a/administrator/components/com_k2/models/tags.php b/administrator/components/com_k2/models/tags.php new file mode 100644 index 0000000..1934063 --- /dev/null +++ b/administrator/components/com_k2/models/tags.php @@ -0,0 +1,175 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', 'id', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', 'DESC', 'word'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', -1, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + + $query = "SELECT #__k2_tags.*, (SELECT COUNT(*) FROM #__k2_tags_xref WHERE #__k2_tags_xref.tagID = #__k2_tags.id) AS numOfItems FROM #__k2_tags"; + + $conditions = array(); + + if ($filter_state > -1) + { + $conditions[] = "published={$filter_state}"; + } + if ($search) + { + $escaped = K2_JVERSION == '15' ? $db->getEscaped($search, true) : $db->escape($search, true); + $conditions[] = "LOWER( name ) LIKE ".$db->Quote('%'.$escaped.'%', false); + } + + if (count($conditions)) + { + $query .= " WHERE ".implode(' AND ', $conditions); + } + + if (!$filter_order) + { + $filter_order = "name"; + } + + $query .= " ORDER BY {$filter_order} {$filter_order_Dir}"; + + $db->setQuery($query, $limitstart, $limit); + $rows = $db->loadObjectList(); + return $rows; + } + + function getTotal() + { + + $mainframe = JFactory::getApplication(); + $option = JRequest::getCmd('option'); + $view = JRequest::getCmd('view'); + $db = JFactory::getDBO(); + $limit = $mainframe->getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.'.limitstart', 'limitstart', 0, 'int'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', 1, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + + $query = "SELECT COUNT(*) FROM #__k2_tags WHERE id>0"; + + if ($filter_state > -1) + { + $query .= " AND published={$filter_state}"; + } + + if ($search) + { + $escaped = K2_JVERSION == '15' ? $db->getEscaped($search, true) : $db->escape($search, true); + $query .= " AND LOWER( name ) LIKE ".$db->Quote('%'.$escaped.'%', false); + } + + $db->setQuery($query); + $total = $db->loadresult(); + return $total; + } + + function publish() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Tag', 'Table'); + $row->load($id); + $row->publish($id, 1); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=tags'); + } + + function unpublish() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Tag', 'Table'); + $row->load($id); + $row->publish($id, 0); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=tags'); + } + + function remove() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Tag', 'Table'); + $row->load($id); + $row->delete($id); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=tags', JText::_('K2_DELETE_COMPLETED')); + } + + function getFilter() + { + + $db = JFactory::getDBO(); + $query = "SELECT name, id FROM #__k2_tags ORDER BY name"; + $db->setQuery($query, 0, 1000); + $rows = $db->loadObjectList(); + return $rows; + + } + + function countTagItems($id) + { + $db = JFactory::getDBO(); + $query = "SELECT COUNT(*) FROM #__k2_tags_xref WHERE tagID = ".(int)$id; + $db->setQuery($query); + $result = $db->loadResult(); + return $result; + } + + function removeOrphans() + { + $db = JFactory::getDBO(); + $db->setQuery("DELETE FROM #__k2_tags WHERE id NOT IN (SELECT DISTINCT tagID FROM #__k2_tags_xref)"); + $db->query(); + $mainframe = JFactory::getApplication(); + $mainframe->redirect('index.php?option=com_k2&view=tags', JText::_('K2_DELETE_COMPLETED')); + } + +} diff --git a/administrator/components/com_k2/models/user.php b/administrator/components/com_k2/models/user.php new file mode 100644 index 0000000..a0f48d2 --- /dev/null +++ b/administrator/components/com_k2/models/user.php @@ -0,0 +1,196 @@ +setQuery($query); + $row = $db->loadObject(); + if (!$row) + { + $row = JTable::getInstance('K2User', 'Table'); + } + return $row; + } + + function save() + { + + $mainframe = JFactory::getApplication(); + jimport('joomla.filesystem.file'); + require_once (JPATH_COMPONENT.DS.'lib'.DS.'class.upload.php'); + $row = JTable::getInstance('K2User', 'Table'); + $params = JComponentHelper::getParams('com_k2'); + + if (!$row->bind(JRequest::get('post'))) + { + $mainframe->redirect('index.php?option=com_k2&view=users', $row->getError(), 'error'); + } + + $row->description = JRequest::getVar('description', '', 'post', 'string', 2); + if ($params->get('xssFiltering')) + { + $filter = new JFilterInput( array(), array(), 1, 1, 0); + $row->description = $filter->clean($row->description); + } + $jUser = JFactory::getUser($row->userID); + $row->userName = $jUser->name; + + if (!$row->store()) + { + $mainframe->redirect('index.php?option=com_k2&view=users', $row->getError(), 'error'); + } + + //Image + if ((int)$params->get('imageMemoryLimit')) + { + ini_set('memory_limit', (int)$params->get('imageMemoryLimit').'M'); + } + + $file = JRequest::get('files'); + + $savepath = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'users'.DS; + + if ($file['image']['error'] == 0 && !JRequest::getBool('del_image')) + { + $handle = new Upload($file['image']); + if ($handle->uploaded) + { + $handle->file_auto_rename = false; + $handle->file_overwrite = true; + $handle->file_new_name_body = $row->id; + $handle->image_resize = true; + $handle->image_ratio_y = true; + $handle->image_x = $params->get('userImageWidth', '100'); + $handle->Process($savepath); + $handle->Clean(); + } + else + { + $mainframe->redirect('index.php?option=com_k2&view=users', $handle->error, 'error'); + } + $row->image = $handle->file_dst_name; + } + + if (JRequest::getBool('del_image')) + { + + $current = JTable::getInstance('K2User', 'Table'); + $current->load($row->id); + if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'users'.DS.$current->image)) + { + JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'users'.DS.$current->image); + } + $row->image = ''; + } + + if (!$row->check()) + { + $mainframe->redirect('index.php?option=com_k2&view=user&cid='.$row->id, $row->getError(), 'error'); + } + + if (!$row->store()) + { + $mainframe->redirect('index.php?option=com_k2&view=users', $row->getError(), 'error'); + } + + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + + switch(JRequest::getCmd('task')) + { + case 'apply' : + $msg = JText::_('K2_CHANGES_TO_USER_SAVED'); + $link = 'index.php?option=com_k2&view=user&cid='.$row->userID; + break; + case 'save' : + default : + $msg = JText::_('K2_USER_SAVED'); + $link = 'index.php?option=com_k2&view=users'; + break; + } + $mainframe->redirect($link, $msg); + } + + function getUserGroups() + { + + $db = JFactory::getDBO(); + $query = "SELECT * FROM #__k2_user_groups"; + $db->setQuery($query); + $rows = $db->loadObjectList(); + return $rows; + } + + function reportSpammer() + { + $mainframe = JFactory::getApplication(); + $params = JComponentHelper::getParams('com_k2'); + $id = (int)$this->getState('id'); + if (!$id) + { + return false; + } + $user = JFactory::getUser(); + if ($user->id == $id) + { + $mainframe->enqueueMessage(JText::_('K2_YOU_CANNOT_REPORT_YOURSELF'), 'error'); + return false; + } + $db = JFactory::getDBO(); + + // Unpublish user comments + $db->setQuery("UPDATE #__k2_comments SET published = 0 WHERE userID = ".$id); + $db->query(); + $mainframe->enqueueMessage(JText::_('K2_USER_COMMENTS_UNPUBLISHED')); + + // Unpublish user items + $db->setQuery("UPDATE #__k2_items SET published = 0 WHERE created_by = ".$id); + $db->query(); + $mainframe->enqueueMessage(JText::_('K2_USER_ITEMS_UNPUBLISHED')); + + // Report the user to http://www.stopforumspam.com/ + // We need the IP for this, so the user has to be a registered K2 user + $spammer = JFactory::getUser($id); + $db->setQuery("SELECT ip FROM #__k2_users WHERE userID=".$id, 0, 1); + $ip = $db->loadResult(); + if ($ip && function_exists('fsockopen') && $params->get('stopForumSpamApiKey')) + { + $data = "username=".$spammer->username."&ip_addr=".$ip."&email=".$spammer->email."&api_key=".$params->get('stopForumSpamApiKey'); + $fp = fsockopen("www.stopforumspam.com", 80); + fputs($fp, "POST /add.php HTTP/1.1\n"); + fputs($fp, "Host: www.stopforumspam.com\n"); + fputs($fp, "Content-type: application/x-www-form-urlencoded\n"); + fputs($fp, "Content-length: ".strlen($data)."\n"); + fputs($fp, "Connection: close\n\n"); + fputs($fp, $data); + fclose($fp); + $mainframe->enqueueMessage(JText::_('K2_USER_DATA_SUBMITTED_TO_STOPFORUMSPAM')); + } + + // Finally block the user + $db->setQuery("UPDATE #__users SET block = 1 WHERE id=".$id); + $db->query(); + $mainframe->enqueueMessage(JText::_('K2_USER_BLOCKED')); + return true; + } + +} diff --git a/administrator/components/com_k2/models/usergroup.php b/administrator/components/com_k2/models/usergroup.php new file mode 100644 index 0000000..537442b --- /dev/null +++ b/administrator/components/com_k2/models/usergroup.php @@ -0,0 +1,66 @@ +load($cid); + return $row; + } + + function save() + { + $mainframe = JFactory::getApplication(); + $row = JTable::getInstance('K2UserGroup', 'Table'); + + if (!$row->bind(JRequest::get('post'))) + { + $mainframe->redirect('index.php?option=com_k2&view=usergroups', $row->getError(), 'error'); + } + + if (!$row->check()) + { + $mainframe->redirect('index.php?option=com_k2&view=usergroup&cid='.$row->id, $row->getError(), 'error'); + } + + if (!$row->store()) + { + $mainframe->redirect('index.php?option=com_k2&view=usergroups', $row->getError(), 'error'); + } + + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + + switch(JRequest::getCmd('task')) + { + case 'apply' : + $msg = JText::_('K2_CHANGES_TO_USER_GROUP_SAVED'); + $link = 'index.php?option=com_k2&view=usergroup&cid='.$row->id; + break; + case 'save' : + default : + $msg = JText::_('K2_USER_GROUP_SAVED'); + $link = 'index.php?option=com_k2&view=usergroups'; + break; + } + $mainframe->redirect($link, $msg); + } + +} diff --git a/administrator/components/com_k2/models/usergroup.xml b/administrator/components/com_k2/models/usergroup.xml new file mode 100644 index 0000000..745d012 --- /dev/null +++ b/administrator/components/com_k2/models/usergroup.xml @@ -0,0 +1,66 @@ + +
    + K2_USER_GROUP_EDIT_FORM + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    \ No newline at end of file diff --git a/administrator/components/com_k2/models/usergroups.php b/administrator/components/com_k2/models/usergroups.php new file mode 100644 index 0000000..9358ffe --- /dev/null +++ b/administrator/components/com_k2/models/usergroups.php @@ -0,0 +1,78 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', '', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', '', 'word'); + + $query = "SELECT userGroup.*, (SELECT COUNT(DISTINCT userID) FROM #__k2_users WHERE `group`=userGroup.id) AS numOfUsers FROM #__k2_user_groups AS userGroup"; + + if (!$filter_order) + { + $filter_order = "name"; + } + + $query .= " ORDER BY {$filter_order} {$filter_order_Dir}"; + + $db->setQuery($query, $limitstart, $limit); + $rows = $db->loadObjectList(); + return $rows; + } + + function getTotal() + { + + $mainframe = JFactory::getApplication(); + $option = JRequest::getCmd('option'); + $view = JRequest::getCmd('view'); + $db = JFactory::getDBO(); + + $query = "SELECT COUNT(*) FROM #__k2_user_groups"; + + $db->setQuery($query); + $total = $db->loadresult(); + return $total; + } + + function remove() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + foreach ($cid as $id) + { + $row = JTable::getInstance('K2UserGroup', 'Table'); + $row->load($id); + $row->delete($id); + } + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=usergroups', JText::_('K2_DELETE_COMPLETED')); + } + +} diff --git a/administrator/components/com_k2/models/users.php b/administrator/components/com_k2/models/users.php new file mode 100644 index 0000000..4bb18d8 --- /dev/null +++ b/administrator/components/com_k2/models/users.php @@ -0,0 +1,560 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', 'juser.name', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', '', 'word'); + $filter_status = $mainframe->getUserStateFromRequest($option.$view.'filter_status', 'filter_status', -1, 'int'); + $filter_group = $mainframe->getUserStateFromRequest($option.$view.'filter_group', 'filter_group', '', 'string'); + $filter_group_k2 = $mainframe->getUserStateFromRequest($option.$view.'filter_group_k2', 'filter_group_k2', '', 'string'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + + $query = "SELECT juser.*, k2user.group, k2group.name as groupname FROM #__users as juser "."LEFT JOIN #__k2_users as k2user ON juser.id=k2user.userID "."LEFT JOIN #__k2_user_groups as k2group ON k2user.group=k2group.id "; + + if (K2_JVERSION != '15') + { + $query .= " LEFT JOIN #__user_usergroup_map as `map` ON juser.id=map.user_id "; + } + + $query .= " WHERE juser.id>0"; + + if ($filter_status > -1) + { + $query .= " AND juser.block = {$filter_status}"; + } + + if ($filter_group) + { + if (K2_JVERSION != '15') + { + $query .= " AND `map`.group_id =".(int)$filter_group; + } + else + { + switch($filter_group) + { + case 'Public Frontend' : + $query .= " AND juser.usertype IN ('Registered', 'Author', 'Editor', 'Publisher')"; + break; + + case 'Public Backend' : + $query .= " AND juser.usertype IN ('Manager', 'Administrator', 'Super Administrator')"; + break; + + default : + $filter_group = strtolower(trim($filter_group)); + $query .= " AND juser.usertype = ".$db->Quote($filter_group); + } + } + + } + + if ($filter_group_k2) + { + $query .= " AND k2user.group = ".$db->Quote($filter_group_k2); + } + + if ($search) + { + $escaped = K2_JVERSION == '15' ? $db->getEscaped($search, true) : $db->escape($search, true); + $query .= " AND (LOWER( juser.name ) LIKE ".$db->Quote('%'.$escaped.'%', false)." OR LOWER( juser.email ) LIKE ".$db->Quote('%'.$escaped.'%', false).")"; + } + + if (!$filter_order) + { + $filter_order = "juser.name"; + } + + if (K2_JVERSION != '15') + { + $query .= " GROUP BY juser.id "; + } + + $query .= " ORDER BY {$filter_order} {$filter_order_Dir}"; + + $db->setQuery($query, $limitstart, $limit); + $rows = $db->loadObjectList(); + + if (K2_JVERSION != '15' && count($rows)) + { + foreach ($rows as $row) + { + $IDs[] = $row->id; + } + $query = "SELECT map.user_id, COUNT(map.group_id) AS group_count,GROUP_CONCAT(g2.title SEPARATOR '\n') AS group_names + FROM #__user_usergroup_map AS map + LEFT JOIN #__usergroups AS g2 + ON g2.id = map.group_id + WHERE map.user_id IN (".implode(',', $IDs).") + GROUP BY map.user_id"; + $db->setQuery($query); + $groups = $db->loadObjectList(); + foreach ($rows as $row) + { + foreach ($groups as $group) + { + if ($row->id == $group->user_id) + { + $row->usertype = nl2br($group->group_names); + } + } + } + } + + return $rows; + } + + function getTotal() + { + + $mainframe = JFactory::getApplication(); + $option = JRequest::getCmd('option'); + $view = JRequest::getCmd('view'); + $db = JFactory::getDBO(); + $limit = $mainframe->getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.'.limitstart', 'limitstart', 0, 'int'); + $filter_status = $mainframe->getUserStateFromRequest($option.$view.'filter_status', 'filter_status', -1, 'int'); + $filter_group = $mainframe->getUserStateFromRequest($option.$view.'filter_group', 'filter_group', '', 'string'); + $filter_group_k2 = $mainframe->getUserStateFromRequest($option.$view.'filter_group_k2', 'filter_group_k2', '', 'string'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + + $query = "SELECT COUNT(DISTINCT juser.id) FROM #__users as juser "."LEFT JOIN #__k2_users as k2user ON juser.id=k2user.userID "."LEFT JOIN #__k2_user_groups as k2group ON k2user.group=k2group.id "; + + if (K2_JVERSION != '15') + { + $query .= " LEFT JOIN #__user_usergroup_map as `map` ON juser.id=map.user_id "; + } + + $query .= " WHERE juser.id>0"; + + if ($filter_status > -1) + { + $query .= " AND juser.block = {$filter_status}"; + } + + if ($filter_group) + { + if (K2_JVERSION != '15') + { + $query .= " AND `map`.group_id =".(int)$filter_group; + } + else + { + switch($filter_group) + { + case 'Public Frontend' : + $query .= " AND juser.usertype IN ('Registered', 'Author', 'Editor', 'Publisher')"; + break; + + case 'Public Backend' : + $query .= " AND juser.usertype IN ('Manager', 'Administrator', 'Super Administrator')"; + break; + + default : + $filter_group = strtolower(trim($filter_group)); + $query .= " AND juser.usertype = ".$db->Quote($filter_group); + } + } + } + + if ($filter_group_k2) + { + $query .= " AND k2user.group = ".$db->Quote($filter_group_k2); + } + + if ($search) + { + $escaped = K2_JVERSION == '15' ? $db->getEscaped($search, true) : $db->escape($search, true); + $query .= " AND (LOWER( juser.name ) LIKE ".$db->Quote('%'.$escaped.'%', false)." OR LOWER( juser.email ) LIKE ".$db->Quote('%'.$escaped.'%', false).")"; + + } + + $db->setQuery($query); + $total = $db->loadResult(); + return $total; + } + + function remove() + { + + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + JArrayHelper::toInteger($cid); + $db = JFactory::getDBO(); + $query = "DELETE FROM #__k2_users WHERE userID IN(".implode(',', $cid).")"; + $db->setQuery($query); + $db->query(); + $cache = JFactory::getCache('com_k2'); + $cache->clean(); + $mainframe->redirect('index.php?option=com_k2&view=users', JText::_('K2_USER_PROFILE_DELETED')); + } + + function getUserGroups($type = 'joomla') + { + + $db = JFactory::getDBO(); + + if ($type == 'joomla') + { + + $query = 'SELECT (lft - 3) AS lft, name AS value, name AS text'.' FROM #__core_acl_aro_groups'.' WHERE name != "ROOT"'.' AND name != "USERS"'.' ORDER BY `lft` ASC'; + + if (K2_JVERSION != '15') + { + $query = "SELECT a.lft AS lft, a.id AS value, a.title AS text, COUNT(DISTINCT b.id) AS level + FROM #__usergroups AS a + LEFT JOIN #__usergroups AS b + ON a.lft > b.lft + AND a.rgt < b.rgt + GROUP BY a.id + ORDER BY a.lft ASC"; + } + + $db->setQuery($query); + $groups = $db->loadObjectList(); + $userGroups = array(); + + foreach ($groups as $group) + { + if ($group->lft >= 10) + $group->lft = (int)$group->lft - 10; + if (K2_JVERSION != '15') + { + $group->text = $this->indent($group->level, '- ').$group->text; + } + else + { + $group->text = $this->indent($group->lft).$group->text; + } + + array_push($userGroups, $group); + } + + } + else + { + $query = "SELECT * FROM #__k2_user_groups"; + $db->setQuery($query); + $userGroups = $db->loadObjectList(); + + } + + return $userGroups; + } + + function indent($times, $char = '    ', $start_char = '', $end_char = '') + { + $return = $start_char; + for ($i = 0; $i < $times; $i++) + $return .= $char; + $return .= $end_char; + return $return; + } + + function checkLogin($id) + { + + $db = JFactory::getDBO(); + $query = "SELECT COUNT(s.userid) FROM #__session AS s WHERE s.userid = ".(int)$id; + $db->setQuery($query); + $result = $db->loadResult(); + return $result; + } + + function hasProfile($id) + { + + $db = JFactory::getDBO(); + $query = "SELECT id FROM #__k2_users WHERE userID = ".(int)$id; + $db->setQuery($query); + $result = $db->loadResult(); + return $result; + } + + function enable() + { + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + JArrayHelper::toInteger($cid); + $db = JFactory::getDBO(); + $query = "UPDATE #__users SET block=0 WHERE id IN(".implode(',', $cid).")"; + $db->setQuery($query); + $db->query(); + $mainframe->redirect('index.php?option=com_k2&view=users', JText::_('K2_USERS_ENABLED')); + } + + function disable() + { + $mainframe = JFactory::getApplication(); + $cid = JRequest::getVar('cid'); + JArrayHelper::toInteger($cid); + $db = JFactory::getDBO(); + $query = "UPDATE #__users SET block=1 WHERE id IN(".implode(',', $cid).")"; + $db->setQuery($query); + $db->query(); + $mainframe->redirect('index.php?option=com_k2&view=users', JText::_('K2_USERS_DISABLED')); + } + + function delete() + { + $mainframe = JFactory::getApplication(); + $user = JFactory::getUser(); + $cid = JRequest::getVar('cid'); + JArrayHelper::toInteger($cid); + $db = JFactory::getDBO(); + if (in_array($user->id, $cid)) + { + foreach ($cid as $key => $id) + { + if ($id == $user->id) + { + unset($cid[$key]); + } + } + $mainframe->enqueueMessage(JText::_('K2_YOU_CANNOT_DELETE_YOURSELF'), 'notice'); + } + if (count($cid) < 1) + { + $mainframe->redirect('index.php?option=com_k2&view=users', JText::_('K2_DELETE_COMPLETED')); + } + if (K2_JVERSION != '15') + { + JPluginHelper::importPlugin('user'); + $dispatcher = JDispatcher::getInstance(); + $iAmSuperAdmin = $user->authorise('core.admin'); + foreach ($cid as $key => $id) + { + $table = JTable::getInstance('user'); + $table->load($id); + $allow = $user->authorise('core.delete', 'com_users'); + // Don't allow non-super-admin to delete a super admin + $allow = (!$iAmSuperAdmin && JAccess::check($id, 'core.admin')) ? false : $allow; + if ($allow) + { + // Get users data for the users to delete. + $user_to_delete = JFactory::getUser($id); + // Fire the onUserBeforeDelete event. + $dispatcher->trigger('onUserBeforeDelete', array($table->getProperties())); + if (!$table->delete($id)) + { + $this->setError($table->getError()); + return false; + } + else + { + // Trigger the onUserAfterDelete event. + $dispatcher->trigger('onUserAfterDelete', array($user_to_delete->getProperties(), true, $this->getError())); + } + } + else + { + // Prune items that you can't change. + unset($cid[$key]); + JError::raiseWarning(403, JText::_('JERROR_CORE_DELETE_NOT_PERMITTED')); + } + } + $IDsToDelete = $cid; + } + else + { + $query = "SELECT * FROM #__users WHERE id IN(".implode(',', $cid).") AND gid<={$user->gid}"; + $db->setQuery($query); + $IDsToDelete = K2_JVERSION == '30' ? $db->loadColumn() : $db->loadResultArray(); + + $query = "DELETE FROM #__users WHERE id IN(".implode(',', $IDsToDelete).") AND id!={$user->id}"; + $db->setQuery($query); + $db->query(); + } + $query = "DELETE FROM #__k2_users WHERE userID IN(".implode(',', $IDsToDelete).") AND userID!={$user->id}"; + $db->setQuery($query); + $db->query(); + + $mainframe->redirect('index.php?option=com_k2&view=users', JText::_('K2_DELETE_COMPLETED')); + } + + function saveMove() + { + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + $cid = JRequest::getVar('cid'); + JArrayHelper::toInteger($cid); + $group = JRequest::getVar('group'); + $k2group = JRequest::getInt('k2group'); + if (K2_JVERSION != '15') + { + JArrayHelper::toInteger($group); + $group = array_filter($group); + if (count($group)) + { + foreach ($cid as $id) + { + $query = "DELETE FROM #__user_usergroup_map WHERE user_id = ".$id; + $db->setQuery($query); + $db->query(); + $query = "INSERT INTO #__user_usergroup_map VALUES (".$id.", ".implode("), (".$id.", ", $group).")"; + $db->setQuery($query); + $db->query(); + } + } + } + else + { + if ($group) + { + $query = "SELECT id FROM #__core_acl_aro_groups WHERE name=".$db->Quote($group); + $db->setQuery($query); + $gid = $db->loadResult(); + $query = "UPDATE #__users SET gid={$gid}, usertype=".$db->Quote($group)." WHERE id IN(".implode(',', $cid).")"; + $db->setQuery($query); + $db->query(); + } + } + + if ($k2group) + { + foreach ($cid as $id) + { + $query = "SELECT COUNT(*) FROM #__k2_users WHERE userID = ".$id; + $db->setQuery($query); + $result = $db->loadResult(); + if ($result) + { + $query = "UPDATE #__k2_users SET `group`={$k2group} WHERE userID = ".$id; + } + else + { + $user = JFactory::getUser($id); + $query = "INSERT INTO #__k2_users VALUES ('', {$id}, {$db->Quote($user->username)}, '', '', '', '', {$k2group}, '')"; + } + $db->setQuery($query); + $db->query(); + } + } + $mainframe->redirect('index.php?option=com_k2&view=users', JText::_('K2_MOVE_COMPLETED')); + + } + + function import() + { + + $mainframe = JFactory::getApplication(); + $db = JFactory::getDBO(); + if (K2_JVERSION != '15') + { + $db->setQuery("SELECT id, title AS name FROM #__usergroups"); + $usergroups = $db->loadObjectList(); + $xml = new JXMLElement(JFile::read(JPATH_COMPONENT.DS.'models'.DS.'usergroup.xml')); + $permissions = class_exists('JParameter') ? new JParameter('') : new JRegistry(''); + foreach ($xml->params as $paramGroup) + { + foreach ($paramGroup->param as $param) + { + $attribute = K2_JVERSION == '30' ? $param->attributes()->type : $param->getAttribute('type'); + if ($attribute != 'spacer') + { + if (K2_JVERSION == '30') + { + $permissions->set((string)$param->attributes()->name, (string)$param->attributes()->default); + } + else + { + $permissions->set($param->getAttribute('name'), $param->getAttribute('default')); + } + + } + } + } + } + else + { + $acl = JFactory::getACL(); + $frontEndGroups = $acl->_getBelow('#__core_acl_aro_groups', 'g1.id, g1.name, COUNT(g2.name) AS level', 'g1.name', false, 'Public Frontend', false); + $backEndGroups = $acl->_getBelow('#__core_acl_aro_groups', 'g1.id, g1.name, COUNT(g2.name) AS level', 'g1.name', false, 'Public Backend', false); + $usergroups = array_merge($frontEndGroups, $backEndGroups); + + $xml = new JSimpleXML; + $xml->loadFile(JPATH_COMPONENT.DS.'models'.DS.'usergroup.xml'); + $permissions = class_exists('JParameter') ? new JParameter('') : new JRegistry(''); + foreach ($xml->document->params as $paramGroup) + { + foreach ($paramGroup->param as $param) + { + if ($param->attributes('type') != 'spacer') + { + $permissions->set($param->attributes('name'), $param->attributes('default')); + } + } + } + } + + $permissions->set('inheritance', 0); + $permissions->set('categories', 'all'); + $permissions = $permissions->toString(); + + foreach ($usergroups as $usergroup) + { + $K2UserGroup = JTable::getInstance('K2UserGroup', 'Table'); + $K2UserGroup->name = JString::trim($usergroup->name)." (Imported from Joomla!)"; + $K2UserGroup->permissions = $permissions; + $K2UserGroup->store(); + + if (K2_JVERSION != '15') + { + $query = "SELECT * FROM #__users AS user JOIN #__user_usergroup_map AS map ON user.id = map.user_id + WHERE map.group_id = ".$usergroup->id; + } + else + { + $query = "SELECT * FROM #__users WHERE gid={$usergroup->id}"; + } + + $db->setQuery($query); + $users = $db->loadObjectList(); + + foreach ($users as $user) + { + + $query = "SELECT COUNT(*) FROM #__k2_users WHERE userID={$user->id}"; + $db->setQuery($query); + $result = $db->loadResult(); + if (!$result) + { + $K2User = JTable::getInstance('K2User', 'Table'); + $K2User->userID = $user->id; + $K2User->group = $K2UserGroup->id; + $K2User->store(); + } + } + } + + $mainframe->redirect('index.php?option=com_k2&view=users', JText::_('K2_IMPORT_COMPLETED')); + + } + +} diff --git a/administrator/components/com_k2/script.k2.php b/administrator/components/com_k2/script.k2.php new file mode 100644 index 0000000..cc1824d --- /dev/null +++ b/administrator/components/com_k2/script.k2.php @@ -0,0 +1,401 @@ +modules = array(); + $status->plugins = array(); + $src = $parent->getParent()->getPath('source'); + $manifest = $parent->getParent()->manifest; + $plugins = $manifest->xpath('plugins/plugin'); + foreach ($plugins as $plugin) + { + $name = (string)$plugin->attributes()->plugin; + $group = (string)$plugin->attributes()->group; + $path = $src.'/plugins/'.$group; + if (JFolder::exists($src.'/plugins/'.$group.'/'.$name)) + { + $path = $src.'/plugins/'.$group.'/'.$name; + } + $installer = new JInstaller; + $result = $installer->install($path); + if ($result && $group != 'finder' && $group != 'josetta_ext') + { + if (JFile::exists(JPATH_SITE.'/plugins/'.$group.'/'.$name.'/'.$name.'.xml')) + { + JFile::delete(JPATH_SITE.'/plugins/'.$group.'/'.$name.'/'.$name.'.xml'); + } + JFile::move(JPATH_SITE.'/plugins/'.$group.'/'.$name.'/'.$name.'.j25.xml', JPATH_SITE.'/plugins/'.$group.'/'.$name.'/'.$name.'.xml'); + } + $query = "UPDATE #__extensions SET enabled=1 WHERE type='plugin' AND element=".$db->Quote($name)." AND folder=".$db->Quote($group); + $db->setQuery($query); + $db->query(); + $status->plugins[] = array('name' => $name, 'group' => $group, 'result' => $result); + } + $modules = $manifest->xpath('modules/module'); + foreach ($modules as $module) + { + $name = (string)$module->attributes()->module; + $client = (string)$module->attributes()->client; + if (is_null($client)) + { + $client = 'site'; + } + ($client == 'administrator') ? $path = $src.'/administrator/modules/'.$name : $path = $src.'/modules/'.$name; + + if($client == 'administrator') + { + $db->setQuery("SELECT id FROM #__modules WHERE `module` = ".$db->quote($name)); + $isUpdate = (int)$db->loadResult(); + } + + $installer = new JInstaller; + $result = $installer->install($path); + if ($result) + { + $root = $client == 'administrator' ? JPATH_ADMINISTRATOR : JPATH_SITE; + if (JFile::exists($root.'/modules/'.$name.'/'.$name.'.xml')) + { + JFile::delete($root.'/modules/'.$name.'/'.$name.'.xml'); + } + JFile::move($root.'/modules/'.$name.'/'.$name.'.j25.xml', $root.'/modules/'.$name.'/'.$name.'.xml'); + } + $status->modules[] = array('name' => $name, 'client' => $client, 'result' => $result); + if($client == 'administrator' && !$isUpdate) + { + $position = version_compare(JVERSION, '3.0', '<') && $name == 'mod_k2_quickicons'? 'icon' : 'cpanel'; + $db->setQuery("UPDATE #__modules SET `position`=".$db->quote($position).",`published`='1' WHERE `module`=".$db->quote($name)); + $db->query(); + + $db->setQuery("SELECT id FROM #__modules WHERE `module` = ".$db->quote($name)); + $id = (int)$db->loadResult(); + + $db->setQuery("INSERT IGNORE INTO #__modules_menu (`moduleid`,`menuid`) VALUES (".$id.", 0)"); + $db->query(); + } + } + + if (JFile::exists(JPATH_ADMINISTRATOR.'/components/com_k2/admin.k2.php')) + { + JFile::delete(JPATH_ADMINISTRATOR.'/components/com_k2/admin.k2.php'); + } + + if (JFile::exists(JPATH_ADMINISTRATOR.'/components/com_k2/models/cpanel.php')) + { + JFile::delete(JPATH_ADMINISTRATOR.'/components/com_k2/models/cpanel.php'); + } + if (version_compare(JVERSION, '3.0', 'lt') && JFolder::exists(JPATH_ADMINISTRATOR.'/components/com_joomfish/contentelements')) + { + $elements = $manifest->xpath('joomfish/file'); + foreach ($elements as $element) + { + JFile::copy($src.'/administrator/components/com_joomfish/contentelements/'.$element->data(), JPATH_ADMINISTRATOR.'/components/com_joomfish/contentelements/'.$element->data()); + } + } + + // Clean up empty entries in #__k2_users table caused by an issue in the K2 user plugin. Fix details: http://code.google.com/p/getk2/source/detail?r=1966 + $query = "DELETE FROM #__k2_users WHERE userID = 0"; + $db->setQuery($query); + $db->query(); + + $this->installationResults($status); + + } + + public function uninstall($parent) + { + $db = JFactory::getDBO(); + $status = new stdClass; + $status->modules = array(); + $status->plugins = array(); + $manifest = $parent->getParent()->manifest; + $plugins = $manifest->xpath('plugins/plugin'); + foreach ($plugins as $plugin) + { + $name = (string)$plugin->attributes()->plugin; + $group = (string)$plugin->attributes()->group; + $query = "SELECT `extension_id` FROM #__extensions WHERE `type`='plugin' AND element = ".$db->Quote($name)." AND folder = ".$db->Quote($group); + $db->setQuery($query); + $extensions = $db->loadColumn(); + if (count($extensions)) + { + foreach ($extensions as $id) + { + $installer = new JInstaller; + $result = $installer->uninstall('plugin', $id); + } + $status->plugins[] = array('name' => $name, 'group' => $group, 'result' => $result); + } + + } + $modules = $manifest->xpath('modules/module'); + foreach ($modules as $module) + { + $name = (string)$module->attributes()->module; + $client = (string)$module->attributes()->client; + $db = JFactory::getDBO(); + $query = "SELECT `extension_id` FROM `#__extensions` WHERE `type`='module' AND element = ".$db->Quote($name).""; + $db->setQuery($query); + $extensions = $db->loadColumn(); + if (count($extensions)) + { + foreach ($extensions as $id) + { + $installer = new JInstaller; + $result = $installer->uninstall('module', $id); + } + $status->modules[] = array('name' => $name, 'client' => $client, 'result' => $result); + } + + } + $this->uninstallationResults($status); + } + + public function update($type) + { + $db = JFactory::getDBO(); + $fields = $db->getTableColumns('#__k2_categories'); + if (!array_key_exists('language', $fields)) + { + $query = "ALTER TABLE #__k2_categories ADD `language` CHAR(7) NOT NULL"; + $db->setQuery($query); + $db->query(); + + $query = "ALTER TABLE #__k2_categories ADD INDEX (`language`)"; + $db->setQuery($query); + $db->query(); + } + + $fields = $db->getTableColumns('#__k2_items'); + if (!array_key_exists('featured_ordering', $fields)) + { + $query = "ALTER TABLE #__k2_items ADD `featured_ordering` INT(11) NOT NULL default '0' AFTER `featured`"; + $db->setQuery($query); + $db->query(); + } + if (!array_key_exists('language', $fields)) + { + $query = "ALTER TABLE #__k2_items ADD `language` CHAR(7) NOT NULL"; + $db->setQuery($query); + $db->query(); + + $query = "ALTER TABLE #__k2_items ADD INDEX (`language`)"; + $db->setQuery($query); + $db->query(); + } + + if ($fields['video'] != 'text') + { + $query = "ALTER TABLE #__k2_items MODIFY `video` TEXT"; + $db->setQuery($query); + $db->query(); + } + + if ($fields['introtext'] == 'text') + { + $query = "ALTER TABLE #__k2_items MODIFY `introtext` MEDIUMTEXT"; + $db->setQuery($query); + $db->query(); + } + + if ($fields['fulltext'] == 'text') + { + $query = "ALTER TABLE #__k2_items MODIFY `fulltext` MEDIUMTEXT"; + $db->setQuery($query); + $db->query(); + } + + $query = "SHOW INDEX FROM #__k2_items"; + $db->setQuery($query); + $indexes = $db->loadObjectList(); + $indexExists = false; + foreach ($indexes as $index) + { + if ($index->Key_name == 'search') + $indexExists = true; + } + + if (!$indexExists) + { + $query = "ALTER TABLE #__k2_items ADD FULLTEXT `search` (`title`,`introtext`,`fulltext`,`extra_fields_search`,`image_caption`,`image_credits`,`video_caption`,`video_credits`,`metadesc`,`metakey`)"; + $db->setQuery($query); + $db->query(); + + $query = "ALTER TABLE #__k2_items ADD FULLTEXT (`title`)"; + $db->setQuery($query); + $db->query(); + } + + $query = "SHOW INDEX FROM #__k2_tags"; + $db->setQuery($query); + $indexes = $db->loadObjectList(); + $indexExists = false; + foreach ($indexes as $index) + { + if ($index->Key_name == 'name') + $indexExists = true; + } + + if (!$indexExists) + { + $query = "ALTER TABLE #__k2_tags ADD FULLTEXT (`name`)"; + $db->setQuery($query); + $db->query(); + } + + $query = "SELECT COUNT(*) FROM #__k2_user_groups"; + $db->setQuery($query); + $num = $db->loadResult(); + + if ($num == 0) + { + $query = "INSERT INTO #__k2_user_groups (`id`, `name`, `permissions`) VALUES('', 'Registered', '{\"comment\":\"1\",\"frontEdit\":\"0\",\"add\":\"0\",\"editOwn\":\"0\",\"editAll\":\"0\",\"publish\":\"0\",\"inheritance\":0,\"categories\":\"all\"}')"; + $db->setQuery($query); + $db->Query(); + + $query = "INSERT INTO #__k2_user_groups (`id`, `name`, `permissions`) VALUES('', 'Site Owner', '{\"comment\":\"1\",\"frontEdit\":\"1\",\"add\":\"1\",\"editOwn\":\"1\",\"editAll\":\"1\",\"publish\":\"1\",\"inheritance\":1,\"categories\":\"all\"}')"; + $db->setQuery($query); + $db->Query(); + + } + + $fields = $db->getTableColumns('#__k2_users'); + if (!array_key_exists('ip', $fields)) + { + $query = "ALTER TABLE `#__k2_users` + ADD `ip` VARCHAR( 15 ) NOT NULL , + ADD `hostname` VARCHAR( 255 ) NOT NULL , + ADD `notes` TEXT NOT NULL"; + $db->setQuery($query); + $db->query(); + } + } + private function installationResults($status) + { + $language = JFactory::getLanguage(); + $language->load('com_k2'); + $rows = 0; ?> + K2 +

    + + + + + + + + + + + + + + + + + + modules)): ?> + + + + + + modules as $module): ?> + + + + + + + + plugins)): ?> + + + + + + plugins as $plugin): ?> + + + + + + + + +
    + load('com_k2'); + $rows = 0; + ?> +

    + + + + + + + + + + + + + + + + + + modules)): ?> + + + + + + modules as $module): ?> + + + + + + + + + plugins)): ?> + + + + + + plugins as $plugin): ?> + + + + + + + + +
    + bind($K2CategoriesInstances[$oid]); + } + + $k = $this->_tbl_key; + + if ($oid !== null) + { + $this->$k = $oid; + } + + $oid = $this->$k; + + if ($oid === null) + { + return false; + } + $this->reset(); + + $db = $this->getDBO(); + + $query = 'SELECT *'.' FROM '.$this->_tbl.' WHERE '.$this->_tbl_key.' = '.$db->Quote($oid); + $db->setQuery($query); + $result = $db->loadAssoc(); + if ($result) + { + $K2CategoriesInstances[$oid] = $result; + return $this->bind($K2CategoriesInstances[$oid]); + } + else + { + $this->setError($db->getErrorMsg()); + return false; + } + } + + function check() + { + + jimport('joomla.filter.output'); + $params = JComponentHelper::getParams('com_k2'); + $this->name = JString::trim($this->name); + if ($this->name == '') + { + $this->setError(JText::_('K2_CATEGORY_MUST_HAVE_A_NAME')); + return false; + } + if (empty($this->alias)) + { + $this->alias = $this->name; + } + + if (K2_JVERSION == '15') + { + if (JPluginHelper::isEnabled('system', 'unicodeslug') || JPluginHelper::isEnabled('system', 'jw_unicodeSlugsExtended')) + { + $this->alias = JFilterOutput::stringURLSafe($this->alias); + } + else + { + mb_internal_encoding("UTF-8"); + mb_regex_encoding("UTF-8"); + $this->alias = trim(mb_strtolower($this->alias)); + $this->alias = str_replace('-', ' ', $this->alias); + $this->alias = str_replace('/', '-', $this->alias); + $this->alias = mb_ereg_replace('[[:space:]]+', ' ', $this->alias); + $this->alias = trim(str_replace(' ', '-', $this->alias)); + $this->alias = str_replace('.', '', $this->alias); + $this->alias = str_replace('"', '', $this->alias); + $this->alias = str_replace("'", '', $this->alias); + $stripthese = ',|~|!|@|%|^|(|)|<|>|:|;|{|}|[|]|&|`|„|‹|’|‘|“|â€�|•|›|«|´|»|°|«|»|…'; + $strips = explode('|', $stripthese); + foreach ($strips as $strip) + { + $this->alias = str_replace($strip, '', $this->alias); + } + if (trim(str_replace('-', '', $this->alias)) == '') + { + $datenow = JFactory::getDate(); + $this->alias = $datenow->toFormat("%Y-%m-%d-%H-%M-%S"); + } + $this->alias = trim($this->alias, '-.'); + } + } + else + { + if (JFactory::getConfig()->get('unicodeslugs') == 1) + { + $this->alias = JFilterOutput::stringURLUnicodeSlug($this->alias); + } + // Transliterate properly... + else + { + // Detect the site language we will transliterate + if ($this->language == '*') + { + $langParams = JComponentHelper::getParams('com_languages'); + $languageTag = $langParams->get('site'); + } + else + { + $languageTag = $this->language; + } + $language = JLanguage::getInstance($languageTag); + $this->alias = $language->transliterate($this->alias); + $this->alias = JFilterOutput::stringURLSafe($this->alias); + if (trim(str_replace('-', '', $this->alias)) == '') + { + $this->alias = JFactory::getDate()->format('Y-m-d-H-i-s'); + } + } + } + + if (K2_JVERSION == '15' || $params->get('enforceSEFReplacements')) + { + + $SEFReplacements = array(); + $items = explode(',', $params->get('SEFReplacements')); + foreach ($items as $item) + { + if (!empty($item)) + { + @list($src, $dst) = explode('|', trim($item)); + $SEFReplacements[trim($src)] = trim($dst); + } + } + + foreach ($SEFReplacements as $key => $value) + { + $this->alias = str_replace($key, $value, $this->alias); + } + + $this->alias = trim($this->alias, '-.'); + } + + if (K2_JVERSION == '15') + { + if (trim(str_replace('-', '', $this->alias)) == '') + { + $datenow = JFactory::getDate(); + $this->alias = $datenow->toFormat("%Y-%m-%d-%H-%M-%S"); + } + } + + // Check if alias already exists. If so warn the user + $params = JComponentHelper::getParams('com_k2'); + if ($params->get('k2Sef') && !$params->get('k2SefInsertCatId')) + { + $db = JFactory::getDBO(); + $db->setQuery("SELECT id FROM #__k2_categories WHERE alias = ".$db->quote($this->alias)." AND id != ".(int)$this->id); + $result = count($db->loadObjectList()); + if ($result > 1) + { + $this->alias .= '-'.(int)$result + 1; + $application = JFactory::getApplication(); + $application->enqueueMessage(JText::_('K2_WARNING_DUPLICATE_TITLE_ALIAS_DETECTED'), 'notice'); + } + } + + return true; + + } + + function bind($array, $ignore = '') + { + + if (key_exists('params', $array) && is_array($array['params'])) + { + $registry = new JRegistry(); + $registry->loadArray($array['params']); + $array['params'] = $registry->toString(); + } + + if (key_exists('plugins', $array) && is_array($array['plugins'])) + { + $registry = new JRegistry(); + $registry->loadArray($array['plugins']); + $array['plugins'] = $registry->toString(); + } + + return parent::bind($array, $ignore); + } + +} diff --git a/administrator/components/com_k2/tables/k2comment.php b/administrator/components/com_k2/tables/k2comment.php new file mode 100644 index 0000000..d077f4a --- /dev/null +++ b/administrator/components/com_k2/tables/k2comment.php @@ -0,0 +1,35 @@ +commentText = JString::trim($this->commentText); + } + +} diff --git a/administrator/components/com_k2/tables/k2extrafield.php b/administrator/components/com_k2/tables/k2extrafield.php new file mode 100644 index 0000000..97a1e94 --- /dev/null +++ b/administrator/components/com_k2/tables/k2extrafield.php @@ -0,0 +1,39 @@ +name = JString::trim($this->name); + if ($this->name == '') + { + $this->setError(JText::_('K2_NAME_CANNOT_BE_EMPTY')); + return false; + } + return true; + } +} diff --git a/administrator/components/com_k2/tables/k2extrafieldsgroup.php b/administrator/components/com_k2/tables/k2extrafieldsgroup.php new file mode 100644 index 0000000..8d1d0b5 --- /dev/null +++ b/administrator/components/com_k2/tables/k2extrafieldsgroup.php @@ -0,0 +1,35 @@ +name = JString::trim($this->name); + if ($this->name == '') + { + $this->setError(JText::_('K2_GROUP_MUST_HAVE_A_NAME')); + return false; + } + return true; + } + +} diff --git a/administrator/components/com_k2/tables/k2item.php b/administrator/components/com_k2/tables/k2item.php new file mode 100644 index 0000000..b298f30 --- /dev/null +++ b/administrator/components/com_k2/tables/k2item.php @@ -0,0 +1,324 @@ +title = JString::trim($this->title); + if ($this->title == '') + { + $this->setError(JText::_('K2_ITEM_MUST_HAVE_A_TITLE')); + return false; + } + if (!$this->catid) + { + $this->setError(JText::_('K2_ITEM_MUST_HAVE_A_CATEGORY')); + return false; + } + if (empty($this->alias)) + { + $this->alias = $this->title; + } + + if (K2_JVERSION == '15') + { + if (JPluginHelper::isEnabled('system', 'unicodeslug') || JPluginHelper::isEnabled('system', 'jw_unicodeSlugsExtended')) + { + $this->alias = JFilterOutput::stringURLSafe($this->alias); + } + else + { + mb_internal_encoding("UTF-8"); + mb_regex_encoding("UTF-8"); + $this->alias = trim(mb_strtolower($this->alias)); + $this->alias = str_replace('-', ' ', $this->alias); + $this->alias = str_replace('/', '-', $this->alias); + $this->alias = mb_ereg_replace('[[:space:]]+', ' ', $this->alias); + $this->alias = trim(str_replace(' ', '-', $this->alias)); + $this->alias = str_replace('.', '', $this->alias); + $this->alias = str_replace('"', '', $this->alias); + $this->alias = str_replace("'", '', $this->alias); + $stripthese = ',|~|!|@|%|^|(|)|<|>|:|;|{|}|[|]|&|`|„|‹|’|‘|“|â€�|•|›|«|´|»|°|«|»|…'; + $strips = explode('|', $stripthese); + foreach ($strips as $strip) + { + $this->alias = str_replace($strip, '', $this->alias); + } + if (trim(str_replace('-', '', $this->alias)) == '') + { + $datenow = JFactory::getDate(); + $this->alias = $datenow->toFormat("%Y-%m-%d-%H-%M-%S"); + } + $this->alias = trim($this->alias, '-.'); + } + } + else + { + if (JFactory::getConfig()->get('unicodeslugs') == 1) + { + $this->alias = JFilterOutput::stringURLUnicodeSlug($this->alias); + } + // Transliterate properly... + else + { + // Detect the site language we will transliterate + if ($this->language == '*') + { + $langParams = JComponentHelper::getParams('com_languages'); + $languageTag = $langParams->get('site'); + } + else + { + $languageTag = $this->language; + } + $language = JLanguage::getInstance($languageTag); + $this->alias = $language->transliterate($this->alias); + $this->alias = JFilterOutput::stringURLSafe($this->alias); + if (trim(str_replace('-', '', $this->alias)) == '') + { + $this->alias = JFactory::getDate()->format('Y-m-d-H-i-s'); + } + } + } + + if (K2_JVERSION == '15' || $params->get('enforceSEFReplacements')) + { + + $SEFReplacements = array(); + $items = explode(',', $params->get('SEFReplacements')); + foreach ($items as $item) + { + if (!empty($item)) + { + @list($src, $dst) = explode('|', trim($item)); + $SEFReplacements[trim($src)] = trim($dst); + } + } + + foreach ($SEFReplacements as $key => $value) + { + $this->alias = str_replace($key, $value, $this->alias); + } + + $this->alias = trim($this->alias, '-.'); + } + + if (K2_JVERSION == '15') + { + if (trim(str_replace('-', '', $this->alias)) == '') + { + $datenow = JFactory::getDate(); + $this->alias = $datenow->toFormat("%Y-%m-%d-%H-%M-%S"); + } + } + + // Check if alias already exists. If so warn the user + $params = JComponentHelper::getParams('com_k2'); + if ($params->get('k2Sef') && !$params->get('k2SefInsertItemId')) + { + $db = JFactory::getDBO(); + $db->setQuery("SELECT id FROM #__k2_items WHERE alias = ".$db->quote($this->alias)." AND id != ".(int)$this->id); + $result = count($db->loadObjectList()); + if ($result > 1) + { + $this->alias .= '-'.(int)$result + 1; + $application = JFactory::getApplication(); + $application->enqueueMessage(JText::_('K2_WARNING_DUPLICATE_TITLE_ALIAS_DETECTED'), 'notice'); + } + } + return true; + + } + + function bind($array, $ignore = '') + { + + if (key_exists('params', $array) && is_array($array['params'])) + { + $registry = new JRegistry(); + $registry->loadArray($array['params']); + $array['params'] = $registry->toString(); + } + + if (key_exists('plugins', $array) && is_array($array['plugins'])) + { + $registry = new JRegistry(); + $registry->loadArray($array['plugins']); + $array['plugins'] = $registry->toString(); + } + + return parent::bind($array, $ignore); + } + + function getNextOrder($where = '', $column = 'ordering') + { + + $query = "SELECT MAX({$column}) FROM #__k2_items"; + $query .= ($where ? " WHERE ".$where : ""); + $this->_db->setQuery($query); + $maxord = $this->_db->loadResult(); + if ($this->_db->getErrorNum()) + { + $this->setError($this->_db->getErrorMsg()); + return false; + } + return $maxord + 1; + } + + function reorder($where = '', $column = 'ordering') + { + + $k = $this->_tbl_key; + $query = "SELECT {$this->_tbl_key}, {$column} FROM #__k2_items WHERE {$column}>0"; + $query .= ($where ? " AND ".$where : ""); + $query .= " ORDER BY {$column}"; + + $this->_db->setQuery($query); + if (!($orders = $this->_db->loadObjectList())) + { + $this->setError($this->_db->getErrorMsg()); + return false; + } + + for ($i = 0, $n = count($orders); $i < $n; $i++) + { + if ($orders[$i]->$column >= 0) + { + if ($orders[$i]->$column != $i + 1) + { + $orders[$i]->$column = $i + 1; + $query = "UPDATE #__k2_items SET {$column}=".(int)$orders[$i]->$column; + $query .= ' WHERE '.$k.' = '.$this->_db->Quote($orders[$i]->$k); + $this->_db->setQuery($query); + $this->_db->query(); + } + } + } + + return true; + } + + function move($dirn, $where = '', $column = 'ordering') + { + + $k = $this->_tbl_key; + + $sql = "SELECT $this->_tbl_key, {$column} FROM $this->_tbl"; + + if ($dirn < 0) + { + $sql .= ' WHERE '.$column.' < '.(int)$this->$column; + $sql .= ($where ? ' AND '.$where : ''); + $sql .= ' ORDER BY '.$column.' DESC'; + } + else if ($dirn > 0) + { + $sql .= ' WHERE '.$column.' > '.(int)$this->$column; + $sql .= ($where ? ' AND '.$where : ''); + $sql .= ' ORDER BY '.$column; + } + else + { + $sql .= ' WHERE '.$column.' = '.(int)$this->$column; + $sql .= ($where ? ' AND '.$where : ''); + $sql .= ' ORDER BY '.$column; + } + + $this->_db->setQuery($sql, 0, 1); + + $row = null; + $row = $this->_db->loadObject(); + + if (isset($row)) + { + $query = 'UPDATE '.$this->_tbl.' SET '.$column.' = '.(int)$row->$column.' WHERE '.$this->_tbl_key.' = '.$this->_db->Quote($this->$k); + $this->_db->setQuery($query); + + if (!$this->_db->query()) + { + $err = $this->_db->getErrorMsg(); + JError::raiseError(500, $err); + } + + $query = 'UPDATE '.$this->_tbl.' SET '.$column.' = '.(int)$this->$column.' WHERE '.$this->_tbl_key.' = '.$this->_db->Quote($row->$k); + $this->_db->setQuery($query); + + if (!$this->_db->query()) + { + $err = $this->_db->getErrorMsg(); + JError::raiseError(500, $err); + } + $this->$column = $row->$column; + } + else + { + $query = 'UPDATE '.$this->_tbl.' SET '.$column.' = '.(int)$this->$column.' WHERE '.$this->_tbl_key.' = '.$this->_db->Quote($this->$k); + $this->_db->setQuery($query); + + if (!$this->_db->query()) + { + $err = $this->_db->getErrorMsg(); + JError::raiseError(500, $err); + } + } + return true; + } + +} diff --git a/administrator/components/com_k2/tables/k2tag.php b/administrator/components/com_k2/tables/k2tag.php new file mode 100644 index 0000000..bb0a08e --- /dev/null +++ b/administrator/components/com_k2/tables/k2tag.php @@ -0,0 +1,100 @@ +name = JString::trim($this->name); + $this->name = JString::str_ireplace('-', '', $this->name); + $this->name = JString::str_ireplace('.', '', $this->name); + + $params = JComponentHelper::getParams('com_k2'); + if ($params->get('k2TagNorm')) + { + $searches = array('À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'à', 'á', 'â', 'ã', 'ä', 'å', 'Ā', 'ā', 'Ă', 'ă', 'Ą', 'ą', 'Ç', 'ç', 'Ć', 'ć', 'Ĉ', 'ĉ', 'Ċ', 'ċ', 'Č', 'č', 'Ð', 'ð', 'Ď', 'ď', 'Đ', 'đ', 'È', 'É', 'Ê', 'Ë', 'è', 'é', 'ê', 'ë', 'Ē', 'ē', 'Ĕ', 'ĕ', 'Ė', 'ė', 'Ę', 'ę', 'Ě', 'ě', 'Ĝ', 'ĝ', 'Ğ', 'ğ', 'Ġ', 'ġ', 'Ģ', 'ģ', 'Ĥ', 'ĥ', 'Ħ', 'ħ', 'Ì', 'Í', 'Î', 'Ï', 'ì', 'í', 'î', 'ï', 'Ĩ', 'ĩ', 'Ī', 'ī', 'Ĭ', 'ĭ', 'Į', 'į', 'İ', 'ı', 'Ĵ', 'ĵ', 'Ķ', 'ķ', 'ĸ', 'Ĺ', 'ĺ', 'Ļ', 'ļ', 'Ľ', 'ľ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'Ñ', 'ñ', 'Ń', 'ń', 'Ņ', 'ņ', 'Ň', 'ň', 'ʼn', 'Ŋ', 'ŋ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'Ō', 'ō', 'Ŏ', 'ŏ', 'Ő', 'ő', 'Ŕ', 'ŕ', 'Ŗ', 'ŗ', 'Ř', 'ř', 'Ś', 'ś', 'Ŝ', 'ŝ', 'Ş', 'ş', 'Š', 'š', 'ſ', 'Ţ', 'ţ', 'Ť', 'ť', 'Ŧ', 'ŧ', 'Ù', 'Ú', 'Û', 'Ü', 'ù', 'ú', 'û', 'ü', 'Ũ', 'ũ', 'Ū', 'ū', 'Ŭ', 'ŭ', 'Ů', 'ů', 'Ű', 'ű', 'Ų', 'ų', 'Ŵ', 'ŵ', 'Ý', 'ý', 'ÿ', 'Ŷ', 'ŷ', 'Ÿ', 'Ź', 'ź', 'Ż', 'ż', 'Ž', 'ž', 'Ά', 'ά', 'Έ', 'έ', 'Ή', 'ή', 'Ί', 'ί', 'Ό', 'ό', 'Ύ', 'ύ', 'Ώ', 'ώ', 'ϋ', 'ϊ', 'ΐ'); + $replacements = array('A', 'A', 'A', 'A', 'A', 'A', 'a', 'a', 'a', 'a', 'a', 'a', 'A', 'a', 'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'D', 'd', 'D', 'd', 'D', 'd', 'E', 'E', 'E', 'E', 'e', 'e', 'e', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H', 'h', 'I', 'I', 'I', 'I', 'i', 'i', 'i', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'J', 'j', 'K', 'k', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'N', 'n', 'N', 'n', 'N', 'n', 'N', 'n', 'n', 'N', 'n', 'O', 'O', 'O', 'O', 'O', 'O', 'o', 'o', 'o', 'o', 'o', 'o', 'O', 'o', 'O', 'o', 'O', 'o', 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 's', 'T', 't', 'T', 't', 'T', 't', 'U', 'U', 'U', 'U', 'u', 'u', 'u', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'W', 'w', 'Y', 'y', 'y', 'Y', 'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 'Α', 'α', 'Ε', 'ε', 'Η', 'η', 'Ι', 'ι', 'Ο', 'ο', 'Υ', 'υ', 'Ω', 'ω', 'υ', 'ι', 'ι'); + $additionalReplacements = $params->get('k2TagNormAdditionalReplacements'); + $pairs = @explode(',', $additionalReplacements); + if(is_array($pairs)) + { + foreach ($pairs as $pair) { + @list($search, $replace) = @explode('|', $pair); + if(isset($search) && $search && isset($replace) && $replace) + { + $searches[] = $search; + $replacements[] = $replace; + } + } + } + + //$this->name = JString::str_ireplace($searches, $replacements, $this->name); // This causes character stripping in J!1.5!! + $this->name = str_ireplace($searches, $replacements, $this->name); + + // Switch case + if ($params->get('k2TagNormCase') == 'upper') + { + $this->name = JString::strtoupper($this->name); + } + else + { + $this->name = JString::strtolower($this->name); + + // Special case for Greek letter s final + $this->name = JString::str_ireplace('σ ', 'ς ', $this->name); + if(JString::substr($this->name, -1) == 'σ') + { + $this->name = JString::substr($this->name, 0, -1); + $this->name .= 'ς'; + } + } + } + + $this->name = JString::trim($this->name); + if ($this->name == '') + { + $this->setError(JText::_('K2_TAG_CANNOT_BE_EMPTY')); + return false; + } + + if (strlen(utf8_decode($this->name)) < 2) + { + $this->setError(JText::_('K2_TAG_CANNOT_BE_A_SINGLE_CHARACTER')); + return false; + } + + // Check if tag exists already for new tags + if (!$this->id) + { + $this->_db->setQuery("SELECT id FROM #__k2_tags WHERE name = ".$this->_db->Quote($this->name)); + if ($this->_db->loadResult()) + { + $this->setError(JText::_('K2_THIS_TAG_EXISTS_ALREADY')); + return false; + } + } + + return true; + } + +} diff --git a/administrator/components/com_k2/tables/k2user.php b/administrator/components/com_k2/tables/k2user.php new file mode 100644 index 0000000..04ed46a --- /dev/null +++ b/administrator/components/com_k2/tables/k2user.php @@ -0,0 +1,56 @@ +url) != '' && substr($this->url, 0, 7) != 'http://') + $this->url = 'http://'.$this->url; + return true; + } + + function bind($array, $ignore = '') + { + + if (key_exists('plugins', $array) && is_array($array['plugins'])) + { + $registry = new JRegistry(); + $registry->loadArray($array['plugins']); + $array['plugins'] = $registry->toString(); + } + + return parent::bind($array, $ignore); + } + +} diff --git a/administrator/components/com_k2/tables/k2usergroup.php b/administrator/components/com_k2/tables/k2usergroup.php new file mode 100644 index 0000000..9709ef1 --- /dev/null +++ b/administrator/components/com_k2/tables/k2usergroup.php @@ -0,0 +1,51 @@ +name = JString::trim($this->name); + if ($this->name == '') + { + $this->setError(JText::_('K2_GROUP_CANNOT_BE_EMPTY')); + return false; + } + return true; + } + + function bind($array, $ignore = '') + { + + if (key_exists('params', $array) && is_array($array['params'])) + { + $registry = new JRegistry(); + $registry->loadArray($array['params']); + if (JRequest::getVar('categories') == 'all' || JRequest::getVar('categories') == 'none') + $registry->set('categories', JRequest::getVar('categories')); + $array['permissions'] = $registry->toString(); + } + return parent::bind($array, $ignore); + } + +} diff --git a/administrator/components/com_k2/tables/table.php b/administrator/components/com_k2/tables/table.php new file mode 100644 index 0000000..6a66edf --- /dev/null +++ b/administrator/components/com_k2/tables/table.php @@ -0,0 +1,27 @@ +addScriptDeclaration(" + Joomla.submitbutton = function(pressbutton) { + if (pressbutton == 'trash') { + var answer = confirm('".JText::_('K2_WARNING_YOU_ARE_ABOUT_TO_TRASH_THE_SELECTED_CATEGORIES_THEIR_CHILDREN_CATEGORIES_AND_ALL_THEIR_INCLUDED_ITEMS', true)."') + if (answer){ + submitform( pressbutton ); + } else { + return; + } + } else { + submitform( pressbutton ); + } + } +"); + +?> + +
    + + + + + +
    + + + + + + lists['categories']; ?> + lists['trash']; ?> lists['state']; ?> + lists['language'])): ?> + lists['language']; ?> + +
    + + + + + + + + + + + + + + + + + + + + lists['language'])): ?> + + + + + + + + + + + + rows as $key => $row) : ?> + + + + + + + + + + + + + + + + + + + lists['language'])): ?> + + + + + + +
    + ', 'c.ordering', @$this->lists['order_Dir'], @$this->lists['order'], null, 'asc', 'K2_ORDER'); ?> + + # + + + + lists['order_Dir'], @$this->lists['order'] ); ?> + + lists['order_Dir'], @$this->lists['order'] ); ?> ordering ?JHTML::_('grid.order', $this->rows ,'filesave.png' ):''; ?> + + + + lists['order_Dir'], @$this->lists['order'] ); ?> + + + + lists['order_Dir'], @$this->lists['order'] ); ?> + + lists['order_Dir'], @$this->lists['order'] ); ?> + + + lists['order_Dir'], @$this->lists['order']); ?> + lists['order_Dir'], @$this->lists['order'] ); ?> +
    + +
    + page->getLimitBox(); ?> +
    + + page->getListFooter(); ?> +
    + canChange): ?> + + + + + + + filter_trash || $row->trash) { $row->checked_out = 0; echo @JHTML::_('grid.checkedout', $row, $key );}?> + + filter_trash): ?> + trash): ?> + treename; ?> (numOfTrashedItems; ?>) + + treename; ?> (numOfItems.' '.JText::_('K2_ACTIVE'); ?> / numOfTrashedItems.' '.JText::_('K2_TRASHED'); ?>) + + + treename; ?> + params->get('showItemsCounterAdmin')): ?> + + (numOfItems.' '.JText::_('K2_ACTIVE'); ?> / numOfTrashedItems.' '.JText::_('K2_TRASHED'); ?>) + + + + + + page->orderUpIcon( $key, $row->parent == 0 || $row->parent == @$this->rows[$key-1]->parent, 'orderup', 'K2_MOVE_UP', $this->ordering); ?> page->orderDownIcon( $key, count($this->rows), $row->parent == 0 || $row->parent == @$this->rows[$key+1]->parent, 'orderdown', 'K2_MOVE_DOWN', $this->ordering ); ?> + ordering)?'':'disabled="disabled"'; ?> class="text_area k2OrderBox" /> + + inheritFrom; ?> + + extra_fields_group; ?> + + template; ?> + + filter_trash || K2_JVERSION != '15')? $row->groupname:JHTML::_('grid.access', $row, $key ); ?> + + status; ?> + + image): ?> + + + + + <?php echo JText::_('K2_PREVIEW_IMAGE'); ?> + + + + language; ?> + id; ?> +
    + + + + + + + +
    diff --git a/administrator/components/com_k2/views/categories/tmpl/element.php b/administrator/components/com_k2/views/categories/tmpl/element.php new file mode 100644 index 0000000..38014a3 --- /dev/null +++ b/administrator/components/com_k2/views/categories/tmpl/element.php @@ -0,0 +1,71 @@ + +
    +

    + + + + + +
    + + + + + + lists['state']; ?> +
    + + + + + + + + + + + + + rows as $key => $row): ?> + + + + + + + + + + + + + + + +
    # lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>
    name); ?>', 'id');">treename; ?>extra_fields_group; ?>groupname; ?>status; ?>id; ?>
    + +
    + page->getLimitBox(); ?> +
    + + page->getListFooter(); ?> +
    + + + + + + + +
    \ No newline at end of file diff --git a/administrator/components/com_k2/views/categories/tmpl/move.php b/administrator/components/com_k2/views/categories/tmpl/move.php new file mode 100644 index 0000000..20abc38 --- /dev/null +++ b/administrator/components/com_k2/views/categories/tmpl/move.php @@ -0,0 +1,46 @@ +addScriptDeclaration(" + Joomla.submitbutton = function(pressbutton) { + if (pressbutton == 'cancel') { + submitform( pressbutton ); + return; + } + if (\$K2.trim(\$K2('#category').val()) == '') { + alert( '".JText::_('K2_YOU_MUST_SELECT_A_PARENT_CATEGORY', true)."' ); + } else { + submitform( pressbutton ); + } + } +"); + +?> + +
    +
    + + lists['categories']; ?> +
    +
    + (rows); ?>) +
      + rows as $row): ?> +
    1. name; ?>
    2. + +
    +
    + + + +
    diff --git a/administrator/components/com_k2/views/categories/view.html.php b/administrator/components/com_k2/views/categories/view.html.php new file mode 100644 index 0000000..fc290e8 --- /dev/null +++ b/administrator/components/com_k2/views/categories/view.html.php @@ -0,0 +1,238 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', 'c.ordering', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', '', 'word'); + $filter_trash = $mainframe->getUserStateFromRequest($option.$view.'filter_trash', 'filter_trash', 0, 'int'); + $filter_category = $mainframe->getUserStateFromRequest($option.$view.'filter_category', 'filter_category', 0, 'int'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', -1, 'int'); + $language = $mainframe->getUserStateFromRequest($option.$view.'language', 'language', '', 'string'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + $model = $this->getModel(); + $total = $model->getTotal(); + $task = JRequest::getCmd('task'); + if ($limitstart > $total - $limit) + { + $limitstart = max(0, (int)(ceil($total / $limit) - 1) * $limit); + JRequest::setVar('limitstart', $limitstart); + } + + $categories = $model->getData(); + $categoryModel = K2Model::getInstance('Category', 'K2Model'); + + $params = JComponentHelper::getParams('com_k2'); + $this->assignRef('params', $params); + + if (K2_JVERSION != '15') + { + $langs = JLanguageHelper::getLanguages(); + $langsMapping = array(); + $langsMapping['*'] = JText::_('K2_ALL'); + foreach ($langs as $lang) + { + $langsMapping[$lang->lang_code] = $lang->title; + } + } + + + for ($i = 0; $i < sizeof($categories); $i++) + { + $categories[$i]->status = K2_JVERSION == '15' ? JHTML::_('grid.published', $categories[$i], $i) : JHtml::_('jgrid.published', $categories[$i]->published, $i, '', $filter_trash == 0 && $task != 'element'); + if ($params->get('showItemsCounterAdmin')) + { + $categories[$i]->numOfItems = $categoryModel->countCategoryItems($categories[$i]->id); + $categories[$i]->numOfTrashedItems = $categoryModel->countCategoryItems($categories[$i]->id, 1); + } + if (K2_JVERSION == '30') + { + $categories[$i]->canChange = $user->authorise('core.edit.state', 'com_k2.category.'.$categories[$i]->id); + } + // Detect the category template + if (K2_JVERSION != '15') + { + $categoryParams = json_decode($categories[$i]->params); + $categories[$i]->template = $categoryParams->theme; + $categories[$i]->language = $categories[$i]->language ? $categories[$i]->language : '*'; + if (isset($langsMapping)) + { + $categories[$i]->language = $langsMapping[$categories[$i]->language]; + } + } + else + { + if (function_exists('parse_ini_string')) + { + $categoryParams = parse_ini_string($categories[$i]->params); + $categories[$i]->template = $categoryParams['theme']; + } + else + { + $categoryParams = new JParameter($categories[$i]->params); + $categories[$i]->template = $categoryParams->get('theme'); + } + } + if (!$categories[$i]->template) + { + $categories[$i]->template = 'default'; + } + } + + $this->assignRef('rows', $categories); + + jimport('joomla.html.pagination'); + $pageNav = new JPagination($total, $limitstart, $limit); + $this->assignRef('page', $pageNav); + + $lists = array(); + $lists['search'] = $search; + $lists['order_Dir'] = $filter_order_Dir; + $lists['order'] = $filter_order; + + $filter_trash_options[] = JHTML::_('select.option', 0, JText::_('K2_CURRENT')); + $filter_trash_options[] = JHTML::_('select.option', 1, JText::_('K2_TRASHED')); + $lists['trash'] = JHTML::_('select.genericlist', $filter_trash_options, 'filter_trash', '', 'value', 'text', $filter_trash); + + $filter_state_options[] = JHTML::_('select.option', -1, JText::_('K2_SELECT_STATE')); + $filter_state_options[] = JHTML::_('select.option', 1, JText::_('K2_PUBLISHED')); + $filter_state_options[] = JHTML::_('select.option', 0, JText::_('K2_UNPUBLISHED')); + $lists['state'] = JHTML::_('select.genericlist', $filter_state_options, 'filter_state', '', 'value', 'text', $filter_state); + + require_once JPATH_ADMINISTRATOR.'/components/com_k2/models/categories.php'; + $categoriesModel = K2Model::getInstance('Categories', 'K2Model'); + $categories_option[] = JHTML::_('select.option', 0, JText::_('K2_SELECT_CATEGORY')); + $categoriesFilter = $categoriesModel->categoriesTree(NULL, true, false); + $categories_options = @array_merge($categories_option, $categoriesFilter); + $lists['categories'] = JHTML::_('select.genericlist', $categories_options, 'filter_category', '', 'value', 'text', $filter_category); + + if (version_compare(JVERSION, '1.6.0', 'ge')) + { + $languages = JHTML::_('contentlanguage.existing', true, true); + array_unshift($languages, JHTML::_('select.option', '', JText::_('K2_SELECT_LANGUAGE'))); + $lists['language'] = JHTML::_('select.genericlist', $languages, 'language', '', 'value', 'text', $language); + } + $this->assignRef('lists', $lists); + + JToolBarHelper::title(JText::_('K2_CATEGORIES'), 'k2.png'); + + if ($filter_trash == 1) + { + JToolBarHelper::custom('restore', 'publish.png', 'publish_f2.png', 'K2_RESTORE', true); + JToolBarHelper::deleteList('K2_ARE_YOU_SURE_YOU_WANT_TO_DELETE_SELECTED_CATEGORIES', 'remove', 'K2_DELETE'); + } + else + { + JToolBarHelper::publishList(); + JToolBarHelper::unpublishList(); + JToolBarHelper::custom('move', 'move.png', 'move_f2.png', 'K2_MOVE', true); + JToolBarHelper::custom('copy', 'copy.png', 'copy_f2.png', 'K2_COPY', true); + JToolBarHelper::editList(); + JToolBarHelper::addNew(); + JToolBarHelper::trash('trash'); + } + + if (K2_JVERSION != '15') + { + JToolBarHelper::preferences('com_k2', 550, 875, 'K2_PARAMETERS'); + } + else + { + $toolbar = JToolBar::getInstance('toolbar'); + $toolbar->appendButton('Popup', 'config', 'Parameters', 'index.php?option=com_k2&view=settings'); + } + + $this->loadHelper('html'); + K2HelperHTML::subMenu(); + + $this->assignRef('filter_trash', $filter_trash); + $template = $mainframe->getTemplate(); + $this->assignRef('template', $template); + $ordering = (($this->lists['order'] == 'c.ordering' || $this->lists['order'] == 'c.parent, c.ordering') && (!$this->filter_trash)); + $this->assignRef('ordering', $ordering); + + // Joomla! 3.0 drag-n-drop sorting variables + if (K2_JVERSION == '30') + { + if ($ordering) + { + JHtml::_('sortablelist.sortable', 'k2CategoriesList', 'adminForm', strtolower($this->lists['order_Dir']), 'index.php?option=com_k2&view=categories&task=saveorder&format=raw'); + } + $document = JFactory::getDocument(); + $document->addScriptDeclaration(' + Joomla.orderTable = function() { + table = document.getElementById("sortTable"); + direction = document.getElementById("directionTable"); + order = table.options[table.selectedIndex].value; + if (order != \''.$this->lists['order'].'\') { + dirn = \'asc\'; + } else { + dirn = direction.options[direction.selectedIndex].value; + } + Joomla.tableOrdering(order, dirn, ""); + }'); + } + + parent::display($tpl); + + } + + function move() + { + + $mainframe = JFactory::getApplication(); + JTable::addIncludePath(JPATH_COMPONENT.DS.'tables'); + $cid = JRequest::getVar('cid'); + + foreach ($cid as $id) + { + $row = &JTable::getInstance('K2Category', 'Table'); + $row->load($id); + $rows[] = $row; + } + + $categoriesModel = K2Model::getInstance('Categories', 'K2Model'); + $categories_option[] = JHTML::_('select.option', 0, JText::_('K2_NONE_ONSELECTLISTS')); + $categories = $categoriesModel->categoriesTree(NULL, true, false); + $categories_options = @array_merge($categories_option, $categories); + foreach ($categories_options as $option) + { + if (in_array($option->value, $cid)) + $option->disable = true; + } + $lists['categories'] = JHTML::_('select.genericlist', $categories_options, 'category', 'class="inputbox" size="8"', 'value', 'text'); + + $this->assignRef('rows', $rows); + $this->assignRef('lists', $lists); + + JToolBarHelper::title(JText::_('K2_MOVE_CATEGORIES'), 'k2.png'); + + JToolBarHelper::custom('saveMove', 'save.png', 'save_f2.png', 'K2_SAVE', false); + JToolBarHelper::cancel(); + + parent::display(); + } + +} diff --git a/administrator/components/com_k2/views/category/tmpl/default.php b/administrator/components/com_k2/views/category/tmpl/default.php new file mode 100644 index 0000000..8e8f9a7 --- /dev/null +++ b/administrator/components/com_k2/views/category/tmpl/default.php @@ -0,0 +1,330 @@ +addScriptDeclaration(" + Joomla.submitbutton = function(pressbutton){ + if (pressbutton == 'cancel') { + submitform( pressbutton ); + return; + } + if (\$K2.trim(\$K2('#name').val()) == '') { + alert( '".JText::_('K2_A_CATEGORY_MUST_AT_LEAST_HAVE_A_TITLE', true)."' ); + } else { + ".$this->onSave." + submitform( pressbutton ); + } + } +"); + +?> + +
    + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lists['language'])): ?> + + + + + +
    + + + +
    + + + +
    + + + lists['parent']; ?> +
    + + + lists['inheritFrom']; ?> +
    + + + lists['extraFieldsGroup']; ?> +
    + + + lists['published']; ?> +
    + + + lists['access']; ?> +
    + + + lists['language']; ?> +
    + + +
    +
      +
    • +
    • +
    + + +
    +
    editor; ?> +
    +
    +
    +
    +
    + + +
    + + + + + +
    + + + + (: ) +
    +
    + + +
    +
    + row->image)): ?> + <?php echo $this->row->name; ?> + + + +
    +
    +
    + + + + K2Plugins)): ?> +
    + K2Plugins as $K2Plugin): ?> + +
    + name; ?> + fields; ?> +
    + + +
    + +
    +
    +
    +

    +
    + +
    +
      + form->getFieldset('category-item-layout') as $field): ?> +
    • + type=='header'): ?> +
      input; ?>
      + type=='Spacer'): ?> +
       
      +
      + +
      label; ?>
      +
      input; ?>
      +
      + +
    • + +
    +
    + + form->render('params', 'category-item-layout'); ?> + +
    +

    +
    + +
    +
      + form->getFieldset('category-view-options') as $field): ?> +
    • + type=='header'): ?> +
      input; ?>
      + type=='Spacer'): ?> +
       
      +
      + +
      label; ?>
      +
      input; ?>
      +
      + +
    • + +
    +
    + + form->render('params', 'category-view-options'); ?> + +
    +

    +
    + +
    +
      + form->getFieldset('item-image-options') as $field): ?> +
    • + type=='header'): ?> +
      input; ?>
      + type=='Spacer'): ?> +
       
      +
      + +
      label; ?>
      +
      input; ?>
      +
      + +
    • + +
    +
    + + form->render('params', 'item-image-options'); ?> + +
    +

    +
    + +
    +
      + form->getFieldset('item-view-options-listings') as $field): ?> +
    • + type=='header'): ?> +
      input; ?>
      + type=='Spacer'): ?> +
       
      +
      + +
      label; ?>
      +
      input; ?>
      +
      + +
    • + +
    +
    + + form->render('params', 'item-view-options-listings'); ?> + +
    +

    +
    + +
    +
      + form->getFieldset('item-view-options') as $field): ?> +
    • + type=='header'): ?> +
      input; ?>
      + type=='Spacer'): ?> +
       
      +
      + +
      label; ?>
      +
      input; ?>
      +
      + +
    • + +
    +
    + + form->render('params', 'item-view-options'); ?> + +
    +

    +
    + +
    +
      + form->getFieldset('category-metadata-information') as $field): ?> +
    • + type=='header'): ?> +
      input; ?>
      + type=='Spacer'): ?> +
       
      +
      + +
      label; ?>
      +
      input; ?>
      +
      + +
    • + +
    +
    + + form->render('params', 'category-metadata-information'); ?> + +
    + aceAclFlag): ?> +

    +
    row->id, true); ?>
    + +
    +
    + + + + + +
    diff --git a/administrator/components/com_k2/views/category/view.html.php b/administrator/components/com_k2/views/category/view.html.php new file mode 100644 index 0000000..17ea347 --- /dev/null +++ b/administrator/components/com_k2/views/category/view.html.php @@ -0,0 +1,129 @@ +getModel(); + $category = $model->getData(); + if (K2_JVERSION == '15') + { + JFilterOutput::objectHTMLSafe($category); + } + else + { + JFilterOutput::objectHTMLSafe($category, ENT_QUOTES, array('params', 'plugins')); + } + if (!$category->id) + $category->published = 1; + $this->assignRef('row', $category); + $wysiwyg = JFactory::getEditor(); + $editor = $wysiwyg->display('description', $category->description, '100%', '250px', '', '', array('pagebreak', 'readmore')); + $this->assignRef('editor', $editor); + $onSave = ''; + if(K2_JVERSION == '30') + { + $onSave = $wysiwyg->save('description'); + } + $this->assignRef('onSave', $onSave); + + $document = JFactory::getDocument(); + /* + $js = " + var K2SitePath = '".JURI::root(true)."/'; + var K2BasePath = '".JURI::base(true)."/'; + "; + */ + $document->addScriptDeclaration("var K2BasePath = '".JURI::base(true)."/';"); + + $lists = array(); + $lists['published'] = JHTML::_('select.booleanlist', 'published', 'class="inputbox"', $category->published); + $lists['access'] = version_compare(JVERSION, '3.0', 'ge') ? JHTML::_('access.level', 'access', $category->access) : JHTML::_('list.accesslevel', $category); + $query = 'SELECT ordering AS value, name AS text FROM #__k2_categories ORDER BY ordering'; + $lists['ordering'] = version_compare(JVERSION, '3.0', 'ge') ? NUll : JHTML::_('list.specificordering', $category, $category->id, $query); + $categories[] = JHTML::_('select.option', '0', JText::_('K2_NONE_ONSELECTLISTS')); + + require_once JPATH_ADMINISTRATOR.'/components/com_k2/models/categories.php'; + $categoriesModel = K2Model::getInstance('Categories', 'K2Model'); + $tree = $categoriesModel->categoriesTree($category, true, false); + $categories = array_merge($categories, $tree); + $lists['parent'] = JHTML::_('select.genericlist', $categories, 'parent', 'class="inputbox"', 'value', 'text', $category->parent); + + $extraFieldsModel = K2Model::getInstance('ExtraFields', 'K2Model'); + $groups = $extraFieldsModel->getGroups(); + $group[] = JHTML::_('select.option', '0', JText::_('K2_NONE_ONSELECTLISTS'), 'id', 'name'); + $group = array_merge($group, $groups); + $lists['extraFieldsGroup'] = JHTML::_('select.genericlist', $group, 'extraFieldsGroup', 'class="inputbox" size="1" ', 'id', 'name', $category->extraFieldsGroup); + + if (version_compare(JVERSION, '1.6.0', 'ge')) + { + $languages = JHTML::_('contentlanguage.existing', true, true); + $lists['language'] = JHTML::_('select.genericlist', $languages, 'language', '', 'value', 'text', $category->language); + } + + JPluginHelper::importPlugin('k2'); + $dispatcher = JDispatcher::getInstance(); + $K2Plugins = $dispatcher->trigger('onRenderAdminForm', array(&$category, 'category')); + $this->assignRef('K2Plugins', $K2Plugins); + + $params = JComponentHelper::getParams('com_k2'); + $this->assignRef('params', $params); + + if (version_compare(JVERSION, '1.6.0', 'ge')) + { + jimport('joomla.form.form'); + $form = JForm::getInstance('categoryForm', JPATH_COMPONENT_ADMINISTRATOR.DS.'models'.DS.'category.xml'); + $values = array('params' => json_decode($category->params)); + $form->bind($values); + $inheritFrom = (isset($values['params']->inheritFrom)) ? $values['params']->inheritFrom : 0; + } + else + { + $form = new JParameter('', JPATH_COMPONENT_ADMINISTRATOR.DS.'models'.DS.'category.xml'); + $form->loadINI($category->params); + $inheritFrom = $form->get('inheritFrom'); + } + $this->assignRef('form', $form); + + $categories[0] = JHTML::_('select.option', '0', JText::_('K2_NONE_ONSELECTLISTS')); + $lists['inheritFrom'] = JHTML::_('select.genericlist', $categories, 'params[inheritFrom]', 'class="inputbox"', 'value', 'text', $inheritFrom); + + $this->assignRef('lists', $lists); + (JRequest::getInt('cid')) ? $title = JText::_('K2_EDIT_CATEGORY') : $title = JText::_('K2_ADD_CATEGORY'); + JToolBarHelper::title($title, 'k2.png'); + JToolBarHelper::save(); + JToolBarHelper::custom('saveAndNew', 'save.png', 'save_f2.png', 'K2_SAVE_AND_NEW', false); + JToolBarHelper::apply(); + JToolBarHelper::cancel(); + + // ACE ACL integration + $definedConstants = get_defined_constants(); + if (!empty($definedConstants['ACEACL']) && AceaclApi::authorize('permissions', 'com_aceacl')) + { + $aceAclFlag = true; + } + else + { + $aceAclFlag = false; + } + $this->assignRef('aceAclFlag', $aceAclFlag); + + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/views/comments/tmpl/default.php b/administrator/components/com_k2/views/comments/tmpl/default.php new file mode 100644 index 0000000..6888283 --- /dev/null +++ b/administrator/components/com_k2/views/comments/tmpl/default.php @@ -0,0 +1,225 @@ + + +
    + mainframe->isSite()): ?> +
    +
    + + + + + + + +
    + + + + + +
    +
    +

    +
    +
    +
    + + + + + + +
    + + + + + + lists['categories']; ?> + mainframe->isAdmin()): ?> + lists['authors']; ?> + + lists['state']; ?> +
    + + + + + + + + + + + + + + + + + + + + + + + + + + rows as $key=>$row): ?> + + + + + + + + + + + + + + + + + + +
    + # + + + + lists['order_Dir'], @$this->lists['order'] ); ?> + + lists['order_Dir'], @$this->lists['order'] ); ?> + + lists['order_Dir'], @$this->lists['order'] ); ?> + + lists['order_Dir'], @$this->lists['order'] ); ?> + + lists['order_Dir'], @$this->lists['order'] ); ?> + + + + + + lists['order_Dir'], @$this->lists['order'] ); ?> + + lists['order_Dir'], @$this->lists['order'] ); ?> + + + + lists['order_Dir'], @$this->lists['order'] ); ?> + + lists['order_Dir'], @$this->lists['order'] ); ?> +
    +
    + +
    + page->getLimitBox(); ?> +
    + + page->getListFooter(); ?> +
    +
    + + + checked_out = 0; echo @JHTML::_('grid.checkedout', $row, $key ); ?> + +
    commentText; ?>
    +
    +
    +
    + +
    + status; ?> + + mainframe->isAdmin() && $row->userID): ?> + userName; ?> + + userName; ?> + + + commentEmail; ?> + + commentURL); ?> + + commenterLastVisitIP): ?> + + commenterLastVisitIP; ?> + + + + reportUserLink): ?> + × + + + title; ?> + + catName; ?> + + created_by); echo $user->name; ?> + + commentDate , $this->dateFormat); ?> + + id; ?> +
    + + + + + + + + + + + mainframe->isSite()): ?> +
    +
    + +
    diff --git a/administrator/components/com_k2/views/comments/view.html.php b/administrator/components/com_k2/views/comments/view.html.php new file mode 100644 index 0000000..5f071be --- /dev/null +++ b/administrator/components/com_k2/views/comments/view.html.php @@ -0,0 +1,207 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', 'c.id', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', 'DESC', 'word'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', -1, 'int'); + $filter_category = $mainframe->getUserStateFromRequest($option.$view.'filter_category', 'filter_category', 0, 'int'); + $filter_author = $mainframe->getUserStateFromRequest($option.$view.'filter_author', 'filter_author', 0, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + if ($mainframe->isSite()) + { + $filter_author = $user->id; + JRequest::setVar('filter_author', $user->id); + } + $this->loadHelper('html'); + K2Model::addIncludePath(JPATH_COMPONENT_ADMINISTRATOR.DS.'models'); + $model = K2Model::getInstance('Comments', 'K2Model'); + $params = JComponentHelper::getParams('com_k2'); + $total = $model->getTotal(); + if ($limitstart > $total - $limit) + { + $limitstart = max(0, (int)(ceil($total / $limit) - 1) * $limit); + JRequest::setVar('limitstart', $limitstart); + } + $comments = $model->getData(); + + $reportLink = $mainframe->isAdmin() ? 'index.php?option=com_k2&view=user&task=report&id=' : 'index.php?option=com_k2&view=comments&task=reportSpammer&id='; + foreach ($comments as $key => $comment) + { + $comment->reportUserLink = false; + $comment->commenterLastVisitIP = NULL; + if ($comment->userID) + { + + $db = JFactory::getDBO(); + $db->setQuery("SELECT ip FROM #__k2_users WHERE userID = ".$comment->userID); + $comment->commenterLastVisitIP = $db->loadResult(); + + $commenter = JFactory::getUser($comment->userID); + if ($commenter->name) + { + $comment->userName = $commenter->name; + } + if ($mainframe->isSite()) + { + if (K2_JVERSION != '15') + { + if ($user->authorise('core.admin', 'com_k2')) + { + $comment->reportUserLink = JRoute::_($reportLink.$comment->userID); + } + } + else + { + if ($user->gid > 24) + { + $comment->reportUserLink = JRoute::_($reportLink.$comment->userID); + } + } + } + else + { + $comment->reportUserLink = JRoute::_($reportLink.$comment->userID); + } + } + + if ($mainframe->isSite()) + { + $comment->status = K2HelperHTML::stateToggler($comment, $key); + } + else + { + $comment->status = K2_JVERSION == '15' ? JHTML::_('grid.published', $comment, $key) : JHtml::_('jgrid.published', $comment->published, $key); + } + + } + + $this->assignRef('rows', $comments); + + jimport('joomla.html.pagination'); + $pageNav = new JPagination($total, $limitstart, $limit); + $this->assignRef('page', $pageNav); + + $lists = array(); + $lists['search'] = $search; + $lists['order_Dir'] = $filter_order_Dir; + $lists['order'] = $filter_order; + + $filter_state_options[] = JHTML::_('select.option', -1, JText::_('K2_SELECT_STATE')); + $filter_state_options[] = JHTML::_('select.option', 1, JText::_('K2_PUBLISHED')); + $filter_state_options[] = JHTML::_('select.option', 0, JText::_('K2_UNPUBLISHED')); + $lists['state'] = JHTML::_('select.genericlist', $filter_state_options, 'filter_state', '', 'value', 'text', $filter_state); + + require_once JPATH_ADMINISTRATOR.'/components/com_k2/models/categories.php'; + $categoriesModel = K2Model::getInstance('Categories', 'K2Model'); + $categories_option[] = JHTML::_('select.option', 0, JText::_('K2_SELECT_CATEGORY')); + $categories = $categoriesModel->categoriesTree(null, true, false); + $categories_options = @array_merge($categories_option, $categories); + $lists['categories'] = JHTML::_('select.genericlist', $categories_options, 'filter_category', '', 'value', 'text', $filter_category); + + require_once JPATH_ADMINISTRATOR.'/components/com_k2/models/items.php'; + $itemsModel = K2Model::getInstance('Items', 'K2Model'); + $authors = $itemsModel->getItemsAuthors(); + $options = array(); + $options[] = JHTML::_('select.option', 0, '- '.JText::_('K2_NO_USER').' -'); + foreach ($authors as $author) + { + $name = $author->name; + if ($author->block) + { + $name .= ' ['.JText::_('K2_USER_DISABLED').']'; + } + $options[] = JHTML::_('select.option', $author->id, $name); + } + $lists['authors'] = JHTML::_('select.genericlist', $options, 'filter_author', '', 'value', 'text', $filter_author); + $this->assignRef('lists', $lists); + $this->assignRef('mainframe', $mainframe); + + if (K2_JVERSION != '15') + { + $dateFormat = JText::_('K2_J16_DATE_FORMAT'); + } + else + { + $dateFormat = JText::_('K2_DATE_FORMAT'); + } + $this->assignRef('dateFormat', $dateFormat); + + if ($mainframe->isAdmin()) + { + JToolBarHelper::title(JText::_('K2_COMMENTS'), 'k2.png'); + JToolBarHelper::publishList(); + JToolBarHelper::unpublishList(); + JToolBarHelper::deleteList('', 'remove', 'K2_DELETE'); + JToolBarHelper::custom('deleteUnpublished', 'delete', 'delete', 'K2_DELETE_ALL_UNPUBLISHED', false); + $toolbar = JToolBar::getInstance('toolbar'); + + if (K2_JVERSION != '15') + { + JToolBarHelper::preferences('com_k2', 550, 875, 'K2_PARAMETERS'); + } + else + { + $toolbar->appendButton('Popup', 'config', 'Parameters', 'index.php?option=com_k2&view=settings'); + } + K2HelperHTML::subMenu(); + + if (K2_JVERSION != '15') + { + $userEditLink = JURI::base().'index.php?option=com_k2&view=user&cid='; + } + else + { + $userEditLink = JURI::base().'index.php?option=com_k2&view=user&cid='; + } + $this->assignRef('userEditLink', $userEditLink); + + } + + $document = JFactory::getDocument(); + $document->addScriptDeclaration('var K2Language = ["'.JText::_('K2_YOU_CANNOT_EDIT_TWO_COMMENTS_AT_THE_SAME_TIME', true).'", "'.JText::_('K2_THIS_WILL_PERMANENTLY_DELETE_ALL_UNPUBLISHED_COMMENTS_ARE_YOU_SURE', true).'", "'.JText::_('K2_REPORT_USER_WARNING', true).'"];'); + + if ($mainframe->isSite()) + { + // CSS + $document->addStyleSheet(JURI::root(true).'/media/k2/assets/css/k2.frontend.css?v=2.6.7'); + $document->addStyleSheet(JURI::root(true).'/templates/system/css/general.css'); + $document->addStyleSheet(JURI::root(true).'/templates/system/css/system.css'); + if (K2_JVERSION != '15') + { + $document->addStyleSheet(JURI::root(true).'/administrator/templates/bluestork/css/template.css'); + $document->addStyleSheet(JURI::root(true).'/media/system/css/system.css'); + } + else + { + $document->addStyleSheet(JURI::root(true).'/administrator/templates/khepri/css/general.css'); + } + } + + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/views/extrafield/tmpl/default.php b/administrator/components/com_k2/views/extrafield/tmpl/default.php new file mode 100644 index 0000000..3356198 --- /dev/null +++ b/administrator/components/com_k2/views/extrafield/tmpl/default.php @@ -0,0 +1,99 @@ +addScriptDeclaration(" + Joomla.submitbutton = function(pressbutton) { + if (pressbutton == 'cancel') { + submitform( pressbutton ); + return; + } + if (\$K2.trim(\$K2('#group').val()) == '') { + alert( '".JText::_('K2_PLEASE_SELECT_A_GROUP_OR_CREATE_A_NEW_ONE', true)."' ); + } + else if (\$K2.trim(\$K2('#name').val()) == '') { + alert( '".JText::_('K2_NAME_CANNOT_BE_EMPTY', true)."' ); + } + else if (\$K2('#type').val() == '0') { + alert( '".JText::_('K2_PLEASE_SELECT_THE_TYPE_OF_THE_EXTRA_FIELD', true)."' ); + } + else { + submitform( pressbutton ); + } + } +"); + +?> + +
    + + + + + + + + + + + + + + + + + + + + + + row->type == 'header') { echo 'style="display: none;"'; } ?>> + + + + row->type != 'select' && $this->row->type != 'multipleSelect') { echo 'style="display: none;"'; } ?>> + + + + row->type != 'header') { echo 'style="display: none;"'; } ?>> + + + + + + + +
    lists['published']; ?>
    + lists['group']; ?> +
    + + +
    +
    lists['type']; ?>
    + row->required) { echo 'checked="checked"';} ?>/> + row->required) { echo 'checked="checked"';} ?>/> +
    + row->showNull) { echo 'checked="checked"';} ?>/> + row->showNull) { echo 'checked="checked"';} ?>/> +
    + row->displayInFrontEnd) { echo 'checked="checked"';} ?>/> + row->displayInFrontEnd) { echo 'checked="checked"';} ?>/> +
    + + + + + + + + +
    diff --git a/administrator/components/com_k2/views/extrafield/view.html.php b/administrator/components/com_k2/views/extrafield/view.html.php new file mode 100644 index 0000000..f66509f --- /dev/null +++ b/administrator/components/com_k2/views/extrafield/view.html.php @@ -0,0 +1,142 @@ +getModel(); + $extraField = $model->getData(); + if (!$extraField->id) + { + $extraField->published = 1; + $extraField->alias = ''; + $extraField->required = 1; + $extraField->showNull = 0; + $extraField->displayInFrontEnd = 1; + } + else + { + require_once (JPATH_COMPONENT.DS.'lib'.DS.'JSON.php'); + $json = new Services_JSON; + $values = $json->decode($extraField->value); + if (isset($values[0]->alias) && !empty($values[0]->alias)) + { + $extraField->alias = $values[0]->alias; + } + else + { + $extraField->alias = $extraField->name; + } + $searches = array('À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'à', 'á', 'â', 'ã', 'ä', 'å', 'Ā', 'ā', 'Ă', 'ă', 'Ą', 'ą', 'Ç', 'ç', 'Ć', 'ć', 'Ĉ', 'ĉ', 'Ċ', 'ċ', 'Č', 'č', 'Ð', 'ð', 'Ď', 'ď', 'Đ', 'đ', 'È', 'É', 'Ê', 'Ë', 'è', 'é', 'ê', 'ë', 'Ē', 'ē', 'Ĕ', 'ĕ', 'Ė', 'ė', 'Ę', 'ę', 'Ě', 'ě', 'Ĝ', 'ĝ', 'Ğ', 'ğ', 'Ġ', 'ġ', 'Ģ', 'ģ', 'Ĥ', 'ĥ', 'Ħ', 'ħ', 'Ì', 'Í', 'Î', 'Ï', 'ì', 'í', 'î', 'ï', 'Ĩ', 'ĩ', 'Ī', 'ī', 'Ĭ', 'ĭ', 'Į', 'į', 'İ', 'ı', 'Ĵ', 'ĵ', 'Ķ', 'ķ', 'ĸ', 'Ĺ', 'ĺ', 'Ļ', 'ļ', 'Ľ', 'ľ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'Ñ', 'ñ', 'Ń', 'ń', 'Ņ', 'ņ', 'Ň', 'ň', 'ʼn', 'Ŋ', 'ŋ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'Ō', 'ō', 'Ŏ', 'ŏ', 'Ő', 'ő', 'Ŕ', 'ŕ', 'Ŗ', 'ŗ', 'Ř', 'ř', 'Ś', 'ś', 'Ŝ', 'ŝ', 'Ş', 'ş', 'Š', 'š', 'ſ', 'Ţ', 'ţ', 'Ť', 'ť', 'Ŧ', 'ŧ', 'Ù', 'Ú', 'Û', 'Ü', 'ù', 'ú', 'û', 'ü', 'Ũ', 'ũ', 'Ū', 'ū', 'Ŭ', 'ŭ', 'Ů', 'ů', 'Ű', 'ű', 'Ų', 'ų', 'Ŵ', 'ŵ', 'Ý', 'ý', 'ÿ', 'Ŷ', 'ŷ', 'Ÿ', 'Ź', 'ź', 'Ż', 'ż', 'Ž', 'ž', 'α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ', 'ι', 'κ', 'λ', 'μ', 'ν', 'ξ', 'ο', 'π', 'ρ', 'σ', 'τ', 'υ', 'φ', 'χ', 'ψ', 'ω', 'Α', 'Β', 'Γ', 'Δ', 'Ε', 'Ζ', 'Η', 'Θ', 'Ι', 'Κ', 'Λ', 'Μ', 'Ξ', 'Ο', 'Π', 'Ρ', 'Σ', 'Τ', 'Υ', 'Φ', 'Χ', 'Ψ', 'Ω', 'ά', 'έ', 'ή', 'ί', 'ό', 'ύ', 'ώ', 'Ά', 'Έ', 'Ή', 'Ί', 'Ό', 'Ύ', 'Ώ', 'ϊ', 'ΐ', 'ϋ', 'ς', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'А', 'Ӑ', 'Ӓ', 'Ә', 'Ӛ', 'Ӕ', 'Б', 'В', 'Г', 'Ґ', 'Ѓ', 'Ғ', 'Ӷ', 'y', 'Д', 'Е', 'Ѐ', 'Ё', 'Ӗ', 'Ҽ', 'Ҿ', 'Є', 'Ж', 'Ӂ', 'Җ', 'Ӝ', 'З', 'Ҙ', 'Ӟ', 'Ӡ', 'Ѕ', 'И', 'Ѝ', 'Ӥ', 'Ӣ', 'І', 'Ї', 'Ӏ', 'Й', 'Ҋ', 'Ј', 'К', 'Қ', 'Ҟ', 'Ҡ', 'Ӄ', 'Ҝ', 'Л', 'Ӆ', 'Љ', 'М', 'Ӎ', 'Н', 'Ӊ', 'Ң', 'Ӈ', 'Ҥ', 'Њ', 'О', 'Ӧ', 'Ө', 'Ӫ', 'Ҩ', 'П', 'Ҧ', 'Р', 'Ҏ', 'С', 'Ҫ', 'Т', 'Ҭ', 'Ћ', 'Ќ', 'У', 'Ў', 'Ӳ', 'Ӱ', 'Ӯ', 'Ү', 'Ұ', 'Ф', 'Х', 'Ҳ', 'Һ', 'Ц', 'Ҵ', 'Ч', 'Ӵ', 'Ҷ', 'Ӌ', 'Ҹ', 'Џ', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ӹ', 'Ь', 'Ҍ', 'Э', 'Ӭ', 'Ю', 'Я', 'а', 'ӑ', 'ӓ', 'ә', 'ӛ', 'ӕ', 'б', 'в', 'г', 'ґ', 'ѓ', 'ғ', 'ӷ', 'y', 'д', 'е', 'ѐ', 'ё', 'ӗ', 'ҽ', 'ҿ', 'є', 'ж', 'ӂ', 'җ', 'ӝ', 'з', 'ҙ', 'ӟ', 'ӡ', 'ѕ', 'и', 'ѝ', 'ӥ', 'ӣ', 'і', 'ї', 'Ӏ', 'й', 'ҋ', 'ј', 'к', 'қ', 'ҟ', 'ҡ', 'ӄ', 'ҝ', 'л', 'ӆ', 'љ', 'м', 'ӎ', 'н', 'ӊ', 'ң', 'ӈ', 'ҥ', 'њ', 'о', 'ӧ', 'ө', 'ӫ', 'ҩ', 'п', 'ҧ', 'р', 'ҏ', 'с', 'ҫ', 'т', 'ҭ', 'ћ', 'ќ', 'у', 'ў', 'ӳ', 'ӱ', 'ӯ', 'ү', 'ұ', 'ф', 'х', 'ҳ', 'һ', 'ц', 'ҵ', 'ч', 'ӵ', 'ҷ', 'ӌ', 'ҹ', 'џ', 'ш', 'щ', 'ъ', 'ы', 'ӹ', 'ь', 'ҍ', 'э', 'ӭ', 'ю', 'я'); + $replacements = array('A', 'A', 'A', 'A', 'A', 'A', 'a', 'a', 'a', 'a', 'a', 'a', 'A', 'a', 'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'D', 'd', 'D', 'd', 'D', 'd', 'E', 'E', 'E', 'E', 'e', 'e', 'e', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H', 'h', 'I', 'I', 'I', 'I', 'i', 'i', 'i', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'J', 'j', 'K', 'k', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'N', 'n', 'N', 'n', 'N', 'n', 'N', 'n', 'n', 'N', 'n', 'O', 'O', 'O', 'O', 'O', 'O', 'o', 'o', 'o', 'o', 'o', 'o', 'O', 'o', 'O', 'o', 'O', 'o', 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 's', 'T', 't', 'T', 't', 'T', 't', 'U', 'U', 'U', 'U', 'u', 'u', 'u', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'W', 'w', 'Y', 'y', 'y', 'Y', 'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 'a', 'b', 'g', 'd', 'e', 'z', 'h', 'th', 'i', 'k', 'l', 'm', 'n', 'x', 'o', 'p', 'r', 's', 't', 'y', 'f', 'ch', 'ps', 'w', 'A', 'B', 'G', 'D', 'E', 'Z', 'H', 'Th', 'I', 'K', 'L', 'M', 'X', 'O', 'P', 'R', 'S', 'T', 'Y', 'F', 'Ch', 'Ps', 'W', 'a', 'e', 'h', 'i', 'o', 'y', 'w', 'A', 'E', 'H', 'I', 'O', 'Y', 'W', 'i', 'i', 'y', 's', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Zero', 'A', 'A', 'A', 'E', 'E', 'E', 'B', 'V', 'G', 'G', 'G', 'G', 'G', 'Y', 'D', 'E', 'E', 'YO', 'E', 'E', 'E', 'YE', 'ZH', 'DZH', 'ZH', 'DZH', 'Z', 'Z', 'DZ', 'DZ', 'DZ', 'I', 'I', 'I', 'I', 'I', 'JI', 'I', 'Y', 'Y', 'J', 'K', 'Q', 'Q', 'K', 'Q', 'K', 'L', 'L', 'L', 'M', 'M', 'N', 'N', 'N', 'N', 'N', 'N', 'O', 'O', 'O', 'O', 'O', 'P', 'PF', 'P', 'P', 'S', 'S', 'T', 'TH', 'T', 'K', 'U', 'U', 'U', 'U', 'U', 'U', 'U', 'F', 'H', 'H', 'H', 'TS', 'TS', 'CH', 'CH', 'CH', 'CH', 'CH', 'DZ', 'SH', 'SHT', 'A', 'Y', 'Y', 'Y', 'Y', 'E', 'E', 'YU', 'YA', 'a', 'a', 'a', 'e', 'e', 'e', 'b', 'v', 'g', 'g', 'g', 'g', 'g', 'y', 'd', 'e', 'e', 'yo', 'e', 'e', 'e', 'ye', 'zh', 'dzh', 'zh', 'dzh', 'z', 'z', 'dz', 'dz', 'dz', 'i', 'i', 'i', 'i', 'i', 'ji', 'i', 'y', 'y', 'j', 'k', 'q', 'q', 'k', 'q', 'k', 'l', 'l', 'l', 'm', 'm', 'n', 'n', 'n', 'n', 'n', 'n', 'o', 'o', 'o', 'o', 'o', 'p', 'pf', 'p', 'p', 's', 's', 't', 'th', 't', 'k', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'f', 'h', 'h', 'h', 'ts', 'ts', 'ch', 'ch', 'ch', 'ch', 'ch', 'dz', 'sh', 'sht', 'a', 'y', 'y', 'y', 'y', 'e', 'e', 'yu', 'ya'); + $extraField->alias = str_replace($searches, $replacements, $extraField->alias); + $filter = JFilterInput::getInstance(); + $extraField->alias = $filter->clean($extraField->alias, 'WORD'); + + if (isset($values[0]->required)) + { + $extraField->required = $values[0]->required; + } + else + { + $extraField->required = 0; + } + if (isset($values[0]->showNull)) + { + $extraField->showNull = $values[0]->showNull; + } + else + { + $extraField->showNull = 0; + } + if (isset($values[0]->displayInFrontEnd)) + { + $extraField->displayInFrontEnd = $values[0]->displayInFrontEnd; + } + else + { + $extraField->displayInFrontEnd = 0; + } + } + $extraField->name = htmlspecialchars($extraField->name, ENT_QUOTES, 'UTF-8'); + $this->assignRef('row', $extraField); + + $lists = array(); + $lists['published'] = JHTML::_('select.booleanlist', 'published', 'class="inputbox"', $extraField->published); + + $groups[] = JHTML::_('select.option', 0, JText::_('K2_CREATE_NEW_GROUP')); + + $extraFieldModel = K2Model::getInstance('ExtraFields', 'K2Model'); + $uniqueGroups = $extraFieldModel->getGroups(true); + foreach ($uniqueGroups as $group) + { + $groups[] = JHTML::_('select.option', $group->id, $group->name); + } + + $lists['group'] = JHTML::_('select.genericlist', $groups, 'groups', '', 'value', 'text', $extraField->group); + + $typeOptions[] = JHTML::_('select.option', 0, JText::_('K2_SELECT_TYPE')); + $typeOptions[] = JHTML::_('select.option', 'textfield', JText::_('K2_TEXT_FIELD')); + $typeOptions[] = JHTML::_('select.option', 'textarea', JText::_('K2_TEXTAREA')); + $typeOptions[] = JHTML::_('select.option', 'select', JText::_('K2_DROPDOWN_SELECTION')); + $typeOptions[] = JHTML::_('select.option', 'multipleSelect', JText::_('K2_MULTISELECT_LIST')); + $typeOptions[] = JHTML::_('select.option', 'radio', JText::_('K2_RADIO_BUTTONS')); + $typeOptions[] = JHTML::_('select.option', 'link', JText::_('K2_LINK')); + $typeOptions[] = JHTML::_('select.option', 'csv', JText::_('K2_CSV_DATA')); + $typeOptions[] = JHTML::_('select.option', 'labels', JText::_('K2_SEARCHABLE_LABELS')); + $typeOptions[] = JHTML::_('select.option', 'date', JText::_('K2_DATE')); + $typeOptions[] = JHTML::_('select.option', 'image', JText::_('K2_IMAGE')); + $typeOptions[] = JHTML::_('select.option', 'header', JText::_('K2_HEADER')); + $lists['type'] = JHTML::_('select.genericlist', $typeOptions, 'type', '', 'value', 'text', $extraField->type); + + $this->assignRef('lists', $lists); + (JRequest::getInt('cid')) ? $title = JText::_('K2_EDIT_EXTRA_FIELD') : $title = JText::_('K2_ADD_EXTRA_FIELD'); + JToolBarHelper::title($title, 'k2.png'); + JToolBarHelper::save(); + JToolBarHelper::apply(); + JToolBarHelper::cancel(); + JHTML::_('behavior.calendar'); + + $document = JFactory::getDocument(); + $document->addScriptDeclaration(' + var K2BasePath = "'.JURI::base(true).'/"; + var K2Language = [ + "'.JText::_('K2_REMOVE', true).'", + "'.JText::_('K2_OPTIONAL', true).'", + "'.JText::_('K2_COMMA_SEPARATED_VALUES', true).'", + "'.JText::_('K2_USE_EDITOR', true).'", + "'.JText::_('K2_ALL_SETTINGS_ABOVE_ARE_OPTIONAL', true).'", + "'.JText::_('K2_ADD_AN_OPTION', true).'", + "'.JText::_('K2_LINK_TEXT', true).'", + "'.JText::_('K2_URL', true).'", + "'.JText::_('K2_OPEN_IN', true).'", + "'.JText::_('K2_SAME_WINDOW', true).'", + "'.JText::_('K2_NEW_WINDOW', true).'", + "'.JText::_('K2_CLASSIC_JAVASCRIPT_POPUP', true).'", + "'.JText::_('K2_LIGHTBOX_POPUP', true).'", + "'.JText::_('K2_RESET_VALUE', true).'", + "'.JText::_('K2_CALENDAR', true).'", + "'.JText::_('K2_PLEASE_SELECT_A_FIELD_TYPE_FROM_THE_LIST_ABOVE', true).'", + "'.JText::_('K2_COLUMNS', true).'", + "'.JText::_('K2_ROWS', true).'", + ];'); + JHTML::_('behavior.modal'); + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/views/extrafields/tmpl/default.php b/administrator/components/com_k2/views/extrafields/tmpl/default.php new file mode 100644 index 0000000..40ca545 --- /dev/null +++ b/administrator/components/com_k2/views/extrafields/tmpl/default.php @@ -0,0 +1,99 @@ + +
    + + + + + +
    + + + + + + lists['type']; ?> + lists['group']; ?> + lists['state']; ?> +
    + + + + + + + + + + + + + + + + + + + + + rows as $key=>$row): ?> + + + + + + + + + + + + + + + + + + + + + + + +
    + ', 'ordering', @$this->lists['order_Dir'], @$this->lists['order'], null, 'asc', 'K2_ORDER'); ?> + #lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order']); ?> ordering) echo JHTML::_('grid.order', $this->rows ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>
    + + + checked_out = 0; echo @JHTML::_('grid.checkedout', $row, $key ); ?>name; ?>
    : alias; ?>
    groupname; ?> + page->orderUpIcon($key, ($row->group == @$this->rows[$key-1]->group), 'orderup', 'Move Up', $this->ordering); ?> + page->orderDownIcon($key, count($this->rows), ($row->group == @$this->rows[$key+1]->group), 'orderdown', 'Move Down', $this->ordering); ?> + ordering ? '' : 'disabled="disabled"'; ?> + class="text_area" style="text-align: center" /> + type)); ?>status; ?>id; ?>
    + +
    + page->getLimitBox(); ?> +
    + + page->getListFooter(); ?> +
    + + + + + + + +
    \ No newline at end of file diff --git a/administrator/components/com_k2/views/extrafields/view.html.php b/administrator/components/com_k2/views/extrafields/view.html.php new file mode 100644 index 0000000..4d74225 --- /dev/null +++ b/administrator/components/com_k2/views/extrafields/view.html.php @@ -0,0 +1,148 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', 'groupname', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', 'ASC', 'word'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', -1, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + $filter_type = $mainframe->getUserStateFromRequest($option.$view.'filter_type', 'filter_type', '', 'string'); + $filter_group = $mainframe->getUserStateFromRequest($option.$view.'filter_group', 'filter_group', '', 'string'); + + $model = $this->getModel(); + $total = $model->getTotal(); + if ($limitstart > $total - $limit) + { + $limitstart = max(0, (int)(ceil($total / $limit) - 1) * $limit); + JRequest::setVar('limitstart', $limitstart); + } + $extraFields = $model->getData(); + require_once (JPATH_COMPONENT.DS.'lib'.DS.'JSON.php'); + $json = new Services_JSON; + foreach ($extraFields as $key => $extraField) + { + $extraField->status = K2_JVERSION == '15' ? JHTML::_('grid.published', $extraField, $key) : JHtml::_('jgrid.published', $extraField->published, $key); + $values = $json->decode($extraField->value); + if (isset($values[0]->alias) && !empty($values[0]->alias)) + { + $extraField->alias = $values[0]->alias; + } + else + { + $filter = JFilterInput::getInstance(); + $extraField->alias = $filter->clean($extraField->name, 'WORD'); + } + } + $this->assignRef('rows', $extraFields); + + jimport('joomla.html.pagination'); + $pageNav = new JPagination($total, $limitstart, $limit); + $this->assignRef('page', $pageNav); + + $lists = array(); + $lists['search'] = $search; + $lists['order_Dir'] = $filter_order_Dir; + $lists['order'] = $filter_order; + $filter_state_options[] = JHTML::_('select.option', -1, JText::_('K2_SELECT_STATE')); + $filter_state_options[] = JHTML::_('select.option', 1, JText::_('K2_PUBLISHED')); + $filter_state_options[] = JHTML::_('select.option', 0, JText::_('K2_UNPUBLISHED')); + $lists['state'] = JHTML::_('select.genericlist', $filter_state_options, 'filter_state', '', 'value', 'text', $filter_state); + + $extraFieldGroups = $model->getGroups(true); + $groups[] = JHTML::_('select.option', '0', JText::_('K2_SELECT_GROUP')); + + foreach ($extraFieldGroups as $extraFieldGroup) + { + $groups[] = JHTML::_('select.option', $extraFieldGroup->id, $extraFieldGroup->name); + } + $lists['group'] = JHTML::_('select.genericlist', $groups, 'filter_group', '', 'value', 'text', $filter_group); + + $typeOptions[] = JHTML::_('select.option', 0, JText::_('K2_SELECT_TYPE')); + $typeOptions[] = JHTML::_('select.option', 'textfield', JText::_('K2_TEXT_FIELD')); + $typeOptions[] = JHTML::_('select.option', 'textarea', JText::_('K2_TEXTAREA')); + $typeOptions[] = JHTML::_('select.option', 'select', JText::_('K2_DROPDOWN_SELECTION')); + $typeOptions[] = JHTML::_('select.option', 'multipleSelect', JText::_('K2_MULTISELECT_LIST')); + $typeOptions[] = JHTML::_('select.option', 'radio', JText::_('K2_RADIO_BUTTONS')); + $typeOptions[] = JHTML::_('select.option', 'link', JText::_('K2_LINK')); + $typeOptions[] = JHTML::_('select.option', 'csv', JText::_('K2_CSV_DATA')); + $typeOptions[] = JHTML::_('select.option', 'labels', JText::_('K2_SEARCHABLE_LABELS')); + $typeOptions[] = JHTML::_('select.option', 'date', JText::_('K2_DATE')); + $typeOptions[] = JHTML::_('select.option', 'image', JText::_('K2_IMAGE')); + $typeOptions[] = JHTML::_('select.option', 'header', JText::_('K2_HEADER')); + $lists['type'] = JHTML::_('select.genericlist', $typeOptions, 'filter_type', '', 'value', 'text', $filter_type); + + $this->assignRef('lists', $lists); + + JToolBarHelper::title(JText::_('K2_EXTRA_FIELDS'), 'k2.png'); + + JToolBarHelper::publishList(); + JToolBarHelper::unpublishList(); + JToolBarHelper::deleteList('K2_ARE_YOU_SURE_YOU_WANT_TO_DELETE_SELECTED_EXTRA_FIELDS', 'remove', 'K2_DELETE'); + JToolBarHelper::editList(); + JToolBarHelper::addNew(); + + if (K2_JVERSION != '15') + { + JToolBarHelper::preferences('com_k2', 550, 875, 'K2_PARAMETERS'); + } + else + { + $toolbar = JToolBar::getInstance('toolbar'); + $toolbar->appendButton('Popup', 'config', 'Parameters', 'index.php?option=com_k2&view=settings'); + } + + $this->loadHelper('html'); + K2HelperHTML::subMenu(); + + $ordering = ($this->lists['order'] == 'ordering'); + $this->assignRef('ordering', $ordering); + + // Joomla! 3.0 drag-n-drop sorting variables + if (K2_JVERSION == '30') + { + if ($ordering) + { + JHtml::_('sortablelist.sortable', 'k2ExtraFieldsList', 'adminForm', strtolower($this->lists['order_Dir']), 'index.php?option=com_k2&view=extrafields&task=saveorder&format=raw'); + } + $document = JFactory::getDocument(); + $document->addScriptDeclaration(' + Joomla.orderTable = function() { + table = document.getElementById("sortTable"); + direction = document.getElementById("directionTable"); + order = table.options[table.selectedIndex].value; + if (order != \''.$this->lists['order'].'\') { + dirn = \'asc\'; + } else { + dirn = direction.options[direction.selectedIndex].value; + } + Joomla.tableOrdering(order, dirn, ""); + }'); + } + + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/views/extrafieldsgroup/tmpl/default.php b/administrator/components/com_k2/views/extrafieldsgroup/tmpl/default.php new file mode 100644 index 0000000..70abf75 --- /dev/null +++ b/administrator/components/com_k2/views/extrafieldsgroup/tmpl/default.php @@ -0,0 +1,42 @@ +addScriptDeclaration(" + Joomla.submitbutton = function(pressbutton){ + if (pressbutton == 'cancel') { + submitform( pressbutton ); + return; + } + if (\$K2.trim(\$K2('#name').val()) == '') { + alert( '".JText::_('K2_GROUP_NAME_CANNOT_BE_EMPTY', true)."' ); + } else { + submitform( pressbutton ); + } + } +"); + +?> + +
    + + + + + +
    + + + + + +
    diff --git a/administrator/components/com_k2/views/extrafieldsgroup/view.html.php b/administrator/components/com_k2/views/extrafieldsgroup/view.html.php new file mode 100644 index 0000000..5a2bc65 --- /dev/null +++ b/administrator/components/com_k2/views/extrafieldsgroup/view.html.php @@ -0,0 +1,32 @@ +getModel(); + $extraFieldsGroup = $model->getExtraFieldsGroup(); + JFilterOutput::objectHTMLSafe($extraFieldsGroup); + $this->assignRef('row', $extraFieldsGroup); + (JRequest::getInt('cid')) ? $title = JText::_('K2_EDIT_EXTRA_FIELD_GROUP') : $title = JText::_('K2_ADD_EXTRA_FIELD_GROUP'); + JToolBarHelper::title($title, 'k2.png'); + JToolBarHelper::save(); + JToolBarHelper::apply(); + JToolBarHelper::cancel(); + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/views/extrafieldsgroups/tmpl/default.php b/administrator/components/com_k2/views/extrafieldsgroups/tmpl/default.php new file mode 100644 index 0000000..d80fad6 --- /dev/null +++ b/administrator/components/com_k2/views/extrafieldsgroups/tmpl/default.php @@ -0,0 +1,66 @@ +addScriptDeclaration(" + Joomla.submitbutton = function(pressbutton) { + if (pressbutton == 'remove') { + if (confirm('".JText::_('K2_WARNING_ARE_YOU_SURE_YOU_WANT_TO_DELETE_SELECTED_EXTRA_FIELDS_GROUPS_DELETING_THE_GROUPS_WILL_ALSO_DELETE_THE_ASSIGNED_EXTRA_FIELDS', true)."')){ + submitform( pressbutton ); + } + } else { + submitform( pressbutton ); + } + } +"); + +?> + +
    + + + + + + + + + + + + + + + + rows as $key=>$row): ?> + + + + + + + + +
    #
    + +
    + page->getLimitBox(); ?> +
    + + page->getListFooter(); ?> +
    checked_out = 0; echo @JHTML::_('grid.checkedout', $row, $key ); ?>name; ?>categories; ?>
    + + + + + +
    diff --git a/administrator/components/com_k2/views/extrafieldsgroups/view.html.php b/administrator/components/com_k2/views/extrafieldsgroups/view.html.php new file mode 100644 index 0000000..9dfffbd --- /dev/null +++ b/administrator/components/com_k2/views/extrafieldsgroups/view.html.php @@ -0,0 +1,67 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', '', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', '', 'word'); + + $model = $this->getModel(); + $total = $model->getTotalGroups(); + if ($limitstart > $total - $limit) + { + $limitstart = max(0, (int)(ceil($total / $limit) - 1) * $limit); + JRequest::setVar('limitstart', $limitstart); + } + $extraFieldGroups = $model->getGroups(); + + $this->assignRef('rows', $extraFieldGroups); + + jimport('joomla.html.pagination'); + $pageNav = new JPagination($total, $limitstart, $limit); + $this->assignRef('page', $pageNav); + + JToolBarHelper::title(JText::_('K2_EXTRA_FIELD_GROUPS'), 'k2.png'); + + JToolBarHelper::deleteList('', 'remove', 'K2_DELETE'); + JToolBarHelper::editList(); + JToolBarHelper::addNew(); + + if (K2_JVERSION != '15') + { + JToolBarHelper::preferences('com_k2', 550, 875, 'K2_PARAMETERS'); + } + else + { + $toolbar = JToolBar::getInstance('toolbar'); + $toolbar->appendButton('Popup', 'config', 'Parameters', 'index.php?option=com_k2&view=settings'); + } + + $this->loadHelper('html'); + K2HelperHTML::subMenu(); + + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/views/info/tmpl/default.php b/administrator/components/com_k2/views/info/tmpl/default.php new file mode 100644 index 0000000..a8c0681 --- /dev/null +++ b/administrator/components/com_k2/views/info/tmpl/default.php @@ -0,0 +1,318 @@ + +
    + + + + + +
    +
    + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    NuoveXT2.2
    Fugue Icons
    (by Yusuke Kamiyamane)
    3.5.3
    "Choose Your Sport" Icon Pack
    (by TpdkDesign.net)
    Services_JSON1.0.1
    class.upload.php0.32
    jQuery1.5.x - 1.9.x
    jQuery UI1.8.24
    elFinder2.0 (rc1)
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    server; ?>
    php_version; ?>
    db_version; ?>
    gd_check) {$gdinfo=gd_info(); echo $gdinfo["GD Version"];} else echo JText::_('K2_DISABLED'); ?>
    mb_check) echo JText::_('K2_ENABLED'); else echo JText::_('K2_DISABLED'); ?>
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    media/k2media_folder_check) echo JText::_('K2_WRITABLE'); else echo JText::_('K2_NOT_WRITABLE'); ?>
    media/k2/attachmentsattachments_folder_check) echo JText::_('K2_WRITABLE'); else echo JText::_('K2_NOT_WRITABLE'); ?>
    media/k2/categoriescategories_folder_check) echo JText::_('K2_WRITABLE'); else echo JText::_('K2_NOT_WRITABLE'); ?>
    media/k2/galleriesgalleries_folder_check) echo JText::_('K2_WRITABLE'); else echo JText::_('K2_NOT_WRITABLE'); ?>
    media/k2/itemsitems_folder_check) echo JText::_('K2_WRITABLE'); else echo JText::_('K2_NOT_WRITABLE'); ?>
    media/k2/usersusers_folder_check) echo JText::_('K2_WRITABLE'); else echo JText::_('K2_NOT_WRITABLE'); ?>
    media/k2/videosvideos_folder_check) echo JText::_('K2_WRITABLE'); else echo JText::_('K2_NOT_WRITABLE'); ?>
    cachecache_folder_check) echo JText::_('K2_WRITABLE'); else echo JText::_('K2_NOT_WRITABLE'); ?>
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    mod_k2_comments
    mod_k2_content
    mod_k2_tools
    mod_k2_user
    mod_k2_users
    mod_k2_quickicons (administrator)
    mod_k2_stats (administrator)
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    Finder - K2 -
    Search - K2 -
    System - K2 -
    User - K2 -
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + +
     
    +
    +
    +
    diff --git a/administrator/components/com_k2/views/info/view.html.php b/administrator/components/com_k2/views/info/view.html.php new file mode 100644 index 0000000..22c5cab --- /dev/null +++ b/administrator/components/com_k2/views/info/view.html.php @@ -0,0 +1,87 @@ +getVersion(); + $php_version = phpversion(); + $server = $this->get_server_software(); + $gd_check = extension_loaded('gd'); + $mb_check = extension_loaded('mbstring'); + + $media_folder_check = is_writable(JPATH_ROOT.DS.'media'.DS.'k2'); + $attachments_folder_check = is_writable(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'attachments'); + $categories_folder_check = is_writable(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'categories'); + $galleries_folder_check = is_writable(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'galleries'); + $items_folder_check = is_writable(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'items'); + $users_folder_check = is_writable(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'users'); + $videos_folder_check = is_writable(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'videos'); + $cache_folder_check = is_writable(JPATH_ROOT.DS.'cache'); + + $this->assignRef('server', $server); + $this->assignRef('php_version', $php_version); + $this->assignRef('db_version', $db_version); + $this->assignRef('gd_check', $gd_check); + $this->assignRef('mb_check', $mb_check); + + $this->assignRef('media_folder_check', $media_folder_check); + $this->assignRef('attachments_folder_check', $attachments_folder_check); + $this->assignRef('categories_folder_check', $categories_folder_check); + $this->assignRef('galleries_folder_check', $galleries_folder_check); + $this->assignRef('items_folder_check', $items_folder_check); + $this->assignRef('users_folder_check', $users_folder_check); + $this->assignRef('videos_folder_check', $videos_folder_check); + $this->assignRef('cache_folder_check', $cache_folder_check); + + JToolBarHelper::title(JText::_('K2_INFORMATION'), 'k2.png'); + + if (K2_JVERSION != '15') + { + JToolBarHelper::preferences('com_k2', 550, 875, 'K2_PARAMETERS'); + } + else + { + $toolbar = JToolBar::getInstance('toolbar'); + $toolbar->appendButton('Popup', 'config', 'Parameters', 'index.php?option=com_k2&view=settings'); + } + + $this->loadHelper('html'); + K2HelperHTML::subMenu(); + + parent::display($tpl); + } + + function get_server_software() + { + if (isset($_SERVER['SERVER_SOFTWARE'])) + { + return $_SERVER['SERVER_SOFTWARE']; + } + else if (($sf = getenv('SERVER_SOFTWARE'))) + { + return $sf; + } + else + { + return JText::_('K2_NA'); + } + } + +} diff --git a/administrator/components/com_k2/views/item/tmpl/default.php b/administrator/components/com_k2/views/item/tmpl/default.php new file mode 100644 index 0000000..0b9ac9b --- /dev/null +++ b/administrator/components/com_k2/views/item/tmpl/default.php @@ -0,0 +1,960 @@ +addScriptDeclaration(" + Joomla.submitbutton = function(pressbutton){ + if (pressbutton == 'cancel') { + submitform( pressbutton ); + return; + } + if (\$K2.trim(\$K2('#title').val()) == '') { + alert( '".JText::_('K2_ITEM_MUST_HAVE_A_TITLE', true)."' ); + } + else if (\$K2.trim(\$K2('#catid').val()) == '0') { + alert( '".JText::_('K2_PLEASE_SELECT_A_CATEGORY', true)."' ); + } + else { + syncExtraFieldsEditor(); + var validation = validateExtraFields(); + if(validation === true) { + \$K2('#selectedTags option').attr('selected', 'selected'); + submitform( pressbutton ); + } + } + } +"); + +?> + +
    + mainframe->isSite()): ?> +
    +
    + + + + + +
    + + + +
    +
    +

    + +

    +
    +
    +
    + permissions->get('publish')): ?> +
    +

    +
    + + +
    + + + + + + + +
    + + + + + + + + + + + + + + + + + + mainframe->isAdmin() || ($this->mainframe->isSite() && $this->permissions->get('publish'))): ?> + + + + + + + + + +
    + + + +
    + + + +
    + + + lists['categories']; ?> +
    + + + params->get('taggingSystem')): ?> + +
      + row->tags) && count($this->row->tags)): ?> + row->tags as $tag): ?> +
    • + name; ?> + x + +
    • + + +
    • + +
    • +
    • +
    + + + + params->get('lockTags') || $this->user->gid>23): ?> +
    + + +
    +
    +
    + + + + + + + + +
    + lists['tags']; ?> + + +
    +
    + +
    + lists['selectedTags']; ?> +
    + +
    + + + lists['featured']; ?> +
    + + + lists['published']; ?> +
    + + +
    +

    +
      +
    • +
    +
    + + +
    +
      +
    • + params->get('showImageTab')): ?> +
    • + + params->get('showImageGalleryTab')): ?> +
    • + + params->get('showVideoTab')): ?> +
    • + + params->get('showExtraFieldsTab')): ?> +
    • + + params->get('showAttachmentsTab')): ?> +
    • + + K2PluginsItemOther)) && $this->params->get('showK2Plugins')): ?> +
    • + +
    + + +
    + params->get('mergeEditors')): ?> +
    text; ?> +
    +
    +
    + +
    introtext; ?> +
    +
    +
    +
    fulltext; ?> +
    +
    +
    + + K2PluginsItemContent)): ?> +
    + K2PluginsItemContent as $K2Plugin): ?> + +
    + name; ?> + fields; ?> +
    + + +
    + +
    +
    + params->get('showImageTab')): ?> + +
    + + + + + + + + + + + + + + row->image)): ?> + + + + + +
    + + + + (: ) +
    +
    + +
    +
    + + +
    +
    +
    + + + +
    + + + +
    + + + + <?php echo $this->row->title; ?> + + + +
    + K2PluginsItemImage)): ?> +
    + K2PluginsItemImage as $K2Plugin): ?> + +
    + name; ?> + fields; ?> +
    + + +
    + +
    + + params->get('showImageGalleryTab')): ?> + +
    + lists['checkSIG']): ?> + + + + + + + + +
    +
    +
    +
      +
    • +
    +
    +
    + +
    +
    +
    +
    +
      +
    • +
    +
    +
    +
    + +
    +

    +

    +
    + + + K2PluginsItemGallery)): ?> +
    + K2PluginsItemGallery as $K2Plugin): ?> + +
    + name; ?> + fields; ?> +
    + + +
    + +
    + + params->get('showVideoTab')): ?> + +
    + lists['checkAllVideos']): ?> + + + + + + + + + + + + + + row->video): ?> + + + + + +
    + + +
    +
      +
    • +
    • +
    • +
    • +
    +
    +
    + + (: )
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    lists['providers']; ?>

    + +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    + + + +
    + + + +
    + + + row->video; ?> +
    + + +
    + + +
    +
    +
    +
      +
    • +
    +
    +
    + +
    +
    +
    +
    +
      +
    • +
    +
    +
    +
    + +
    +

    +

    +
    + + + + + + + + + + + + + + + row->video): ?> + + + + + +
    + + +
    +
      +
    • +
    +
    +
    + +
    + +
    +
    +
    +
    + + + +
    + + + +
    + + + row->video; ?> +
    + + +
    + + K2PluginsItemVideo)): ?> +
    + K2PluginsItemVideo as $K2Plugin): ?> + +
    + name; ?> + fields; ?> +
    + + +
    + +
    + + params->get('showExtraFieldsTab')): ?> + +
    +
    + extraFields)): ?> + + extraFields as $extraField): ?> + + type == 'header'): ?> + + + + + + + +

    name; ?>

    + + + element; ?> +
    + + +
    +
    +
    +
      +
    • +
    +
    +
    + +
    +
    +
    +
    +
      +
    • +
    +
    +
    +
    + +
    +

    +
    +

    +
    +
    + + +
    + K2PluginsItemExtraFields)): ?> +
    + K2PluginsItemExtraFields as $K2Plugin): ?> + +
    + name; ?> + fields; ?> +
    + + +
    + +
    + + params->get('showAttachmentsTab')): ?> + +
    +
    + row->attachments)): ?> + + + + + + + + + row->attachments as $attachment): ?> + + + + + + + + +
    + + + + + + + + + +
    + filename; ?> + + title; ?> + + titleAttribute; ?> + + hits; ?> + + +
    + +
    +
    + + (: )
    +
    + K2PluginsItemAttachments)): ?> +
    + K2PluginsItemAttachments as $K2Plugin): ?> + +
    + name; ?> + fields; ?> +
    + + +
    + +
    + + K2PluginsItemOther)) && $this->params->get('showK2Plugins')): ?> + +
    +
    + K2PluginsItemOther as $K2Plugin): ?> + +
    + name; ?> + fields; ?> +
    + + +
    +
    + +
    + + + + mainframe->isSite()): ?> + + + + + + + + +
    mainframe->isSite() && !$this->params->get('sideBarDisplayFrontend')): ?> style="display:none;" class="xmlParamsFields"> + row->id): ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + row->id): ?> + + + + +
    + + + row->id; ?> +
    + + + row->published > 0) ? JText::_('K2_YES') : JText::_('K2_NO'); ?> +
    + + + row->featured > 0) ? JText::_('K2_YES'): JText::_('K2_NO'); ?> +
    + + + lists['created']; ?> +
    + + + row->author; ?> +
    + + + lists['modified']; ?> +
    + + + row->moderator; ?> +
    + + + row->hits; ?> + row->hits): ?> + + +
    + + + row->ratingCount; ?> + row->ratingCount): ?> +
    + (: row->ratingSum/$this->row->ratingCount),2); ?>/5.00) + + +
    + +
    +

    +
    + + lists['language'])): ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + lists['language']; ?> +
    + + + row->author; ?> + mainframe->isAdmin() || ($this->mainframe->isSite() && $this->permissions->get('editAll'))): ?> + + + +
    + + + +
    + + + lists['access']; ?> +
    + + + lists['createdCalendar']; ?> +
    + + + lists['publish_up']; ?> +
    + + + lists['publish_down']; ?> +
    +
    +

    +
    + + + + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + + + +
    + + + +
    +
    + mainframe->isAdmin()): ?> +

    +
    + +
    +
      + form->getFieldset('item-view-options-listings') as $field): ?> +
    • + type=='header'): ?> +
      input; ?>
      + type=='Spacer'): ?> +
       
      +
      + +
      label; ?>
      +
      input; ?>
      +
      + +
    • + +
    +
    + + form->render('params', 'item-view-options-listings'); ?> + +
    +

    +
    + +
    +
      + form->getFieldset('item-view-options') as $field): ?> +
    • + type=='header'): ?> +
      input; ?>
      + type=='Spacer'): ?> +
       
      +
      + +
      label; ?>
      +
      input; ?>
      +
      + +
    • + +
    +
    + + form->render('params', 'item-view-options'); ?> + +
    + + aceAclFlag): ?> +

    +
    row->id, true); ?>
    + +
    +
    +
    + mainframe->isSite()): ?> +
    +
    + +
    diff --git a/administrator/components/com_k2/views/item/view.html.php b/administrator/components/com_k2/views/item/view.html.php new file mode 100644 index 0000000..78efe87 --- /dev/null +++ b/administrator/components/com_k2/views/item/view.html.php @@ -0,0 +1,520 @@ +addScript(JURI::root(true).'/media/k2/assets/js/nicEdit.js?v=2.6.7'); + //var K2SitePath = '".JURI::root(true)."/'; + $js = " + var K2BasePath = '".JURI::base(true)."/'; + var K2Language = [ + '".JText::_('K2_REMOVE', true)."', + '".JText::_('K2_LINK_TITLE_OPTIONAL', true)."', + '".JText::_('K2_LINK_TITLE_ATTRIBUTE_OPTIONAL', true)."', + '".JText::_('K2_ARE_YOU_SURE', true)."', + '".JText::_('K2_YOU_ARE_NOT_ALLOWED_TO_POST_TO_THIS_CATEGORY', true)."', + '".JText::_('K2_OR_SELECT_A_FILE_ON_THE_SERVER', true)."' + ] + "; + $document->addScriptDeclaration($js); + K2Model::addIncludePath(JPATH_COMPONENT_ADMINISTRATOR.DS.'models'); + $model = K2Model::getInstance('Item', 'K2Model', array('table_path' => JPATH_COMPONENT_ADMINISTRATOR.DS.'tables')); + $item = $model->getData(); + JFilterOutput::objectHTMLSafe($item, ENT_QUOTES, array('video', 'params', 'plugins')); + $user = JFactory::getUser(); + + // Permissions check on frontend + if ($mainframe->isSite()) + { + JLoader::register('K2HelperPermissions', JPATH_COMPONENT.DS.'helpers'.DS.'permissions.php'); + $task = JRequest::getCmd('task'); + if ($task == 'edit' && !K2HelperPermissions::canEditItem($item->created_by, $item->catid)) + { + JError::raiseError(403, JText::_('K2_ALERTNOTAUTH')); + } + if ($task == 'add' && !K2HelperPermissions::canAddItem()) + { + JError::raiseError(403, JText::_('K2_ALERTNOTAUTH')); + } + // Get permissions + $K2Permissions = K2Permissions::getInstance(); + $this->assignRef('permissions', $K2Permissions->permissions); + } + + if ($item->isCheckedOut($user->get('id'), $item->checked_out)) + { + $message = JText::_('K2_THE_ITEM').': '.$item->title.' '.JText::_('K2_IS_CURRENTLY_BEING_EDITED_BY_ANOTHER_ADMINISTRATOR'); + $url = ($mainframe->isSite()) ? 'index.php?option=com_k2&view=item&id='.$item->id.'&tmpl=component' : 'index.php?option=com_k2'; + $mainframe->redirect($url, $message); + } + + if ($item->id) + { + $item->checkout($user->get('id')); + } + else + { + $item->published = 1; + $item->publish_down = $db->getNullDate(); + $item->modified = $db->getNullDate(); + $date = JFactory::getDate(); + $now = K2_JVERSION == '15' ? $date->toMySQL() : $date->toSql(); + $item->created = $now; + $item->publish_up = $item->created; + } + + $lists = array(); + if (version_compare(JVERSION, '1.6.0', 'ge')) + { + $dateFormat = JText::_('K2_J16_DATE_FORMAT_CALENDAR'); + } + else + { + $dateFormat = JText::_('K2_DATE_FORMAT_CALENDAR'); + } + $item->publish_up = JHTML::_('date', $item->publish_up, $dateFormat); + if ($item->publish_down == $db->getNullDate()) + { + $item->publish_down = ''; + } + else + { + $item->publish_down = JHTML::_('date', $item->publish_down, $dateFormat); + } + + // Set up calendars + $created = JHTML::_('date', $item->created, $dateFormat); + $lists['createdCalendar'] = JHTML::_('calendar', $created, 'created', 'created'); + $lists['publish_up'] = JHTML::_('calendar', $item->publish_up, 'publish_up', 'publish_up'); + $lists['publish_down'] = JHTML::_('calendar', $item->publish_down, 'publish_down', 'publish_down'); + + if ($item->id) + { + $lists['created'] = JHTML::_('date', $item->created, JText::_('DATE_FORMAT_LC2')); + } + else + { + $lists['created'] = JText::_('K2_NEW_DOCUMENT'); + } + + if ($item->modified == $db->getNullDate() || !$item->id) + { + $lists['modified'] = JText::_('K2_NEVER'); + } + else + { + $lists['modified'] = JHTML::_('date', $item->modified, JText::_('DATE_FORMAT_LC2')); + } + + $params = JComponentHelper::getParams('com_k2'); + $wysiwyg = JFactory::getEditor(); + $onSave = ''; + if ($params->get("mergeEditors")) + { + + if (JString::strlen($item->fulltext) > 1) + { + $textValue = $item->introtext."
    ".$item->fulltext; + } + else + { + $textValue = $item->introtext; + } + $text = $wysiwyg->display('text', $textValue, '100%', '400px', '', ''); + $this->assignRef('text', $text); + if(K2_JVERSION == '30') + { + $onSave = $wysiwyg->save('text'); + } + } + else + { + $introtext = $wysiwyg->display('introtext', $item->introtext, '100%', '400px', '', '', array('readmore')); + $this->assignRef('introtext', $introtext); + $fulltext = $wysiwyg->display('fulltext', $item->fulltext, '100%', '400px', '', '', array('readmore')); + $this->assignRef('fulltext', $fulltext); + if(K2_JVERSION == '30') + { + $onSave = $wysiwyg->save('introtext'); + $onSave .= $wysiwyg->save('fulltext'); + } + } + + $document->addScriptDeclaration("function onK2EditorSave(){ ".$onSave." }"); + + $lists['published'] = JHTML::_('select.booleanlist', 'published', 'class="inputbox"', $item->published); + $lists['featured'] = JHTML::_('select.booleanlist', 'featured', 'class="inputbox"', $item->featured); + $lists['access'] = version_compare(JVERSION, '3.0', 'ge') ? JHTML::_('access.level', 'access', $item->access) : JHTML::_('list.accesslevel', $item); + + $query = "SELECT ordering AS value, title AS text FROM #__k2_items WHERE catid={$item->catid}"; + $lists['ordering'] = version_compare(JVERSION, '3.0', 'ge') ? NUll : JHTML::_('list.specificordering', $item, $item->id, $query); + + if (!$item->id) + $item->catid = $mainframe->getUserStateFromRequest('com_k2itemsfilter_category', 'catid', 0, 'int'); + + require_once JPATH_ADMINISTRATOR.'/components/com_k2/models/categories.php'; + $categoriesModel = K2Model::getInstance('Categories', 'K2Model'); + $categories = $categoriesModel->categoriesTree(); + $lists['catid'] = JHTML::_('select.genericlist', $categories, 'catid', 'class="inputbox"', 'value', 'text', $item->catid); + + if (version_compare(JVERSION, '1.6.0', 'ge')) + { + $languages = JHTML::_('contentlanguage.existing', true, true); + $lists['language'] = JHTML::_('select.genericlist', $languages, 'language', '', 'value', 'text', $item->language); + } + + $lists['checkSIG'] = $model->checkSIG(); + $lists['checkAllVideos'] = $model->checkAllVideos(); + + $remoteVideo = false; + $providerVideo = false; + $embedVideo = false; + + if (stristr($item->video, 'remote}') !== false) + { + $remoteVideo = true; + $options['startOffset'] = 1; + } + + $providers = $model->getVideoProviders(); + + if (count($providers)) + { + + foreach ($providers as $provider) + { + $providersOptions[] = JHTML::_('select.option', $provider, ucfirst($provider)); + if (stristr($item->video, "{{$provider}}") !== false) + { + $providerVideo = true; + $options['startOffset'] = 2; + } + } + + } + + if (JString::substr($item->video, 0, 1) !== '{') + { + $embedVideo = true; + $options['startOffset'] = 3; + } + + $lists['uploadedVideo'] = (!$remoteVideo && !$providerVideo && !$embedVideo) ? true : false; + + if ($lists['uploadedVideo'] || $item->video == '') + { + $options['startOffset'] = 0; + } + + $document->addScriptDeclaration("var K2ActiveVideoTab = ".$options['startOffset']); + + $lists['remoteVideo'] = ($remoteVideo) ? preg_replace('%\{[a-z0-9-_]*\}(.*)\{/[a-z0-9-_]*\}%i', '\1', $item->video) : ''; + $lists['remoteVideoType'] = ($remoteVideo) ? preg_replace('%\{([a-z0-9-_]*)\}.*\{/[a-z0-9-_]*\}%i', '\1', $item->video) : ''; + $lists['providerVideo'] = ($providerVideo) ? preg_replace('%\{[a-z0-9-_]*\}(.*)\{/[a-z0-9-_]*\}%i', '\1', $item->video) : ''; + $lists['providerVideoType'] = ($providerVideo) ? preg_replace('%\{([a-z0-9-_]*)\}.*\{/[a-z0-9-_]*\}%i', '\1', $item->video) : ''; + $lists['embedVideo'] = ($embedVideo) ? $item->video : ''; + + if (isset($providersOptions)) + { + $lists['providers'] = JHTML::_('select.genericlist', $providersOptions, 'videoProvider', '', 'value', 'text', $lists['providerVideoType']); + } + + JPluginHelper::importPlugin('content', 'jw_sigpro'); + JPluginHelper::importPlugin('content', 'jw_allvideos'); + + $dispatcher = JDispatcher::getInstance(); + + // Detect gallery type + if (JString::strpos($item->gallery, 'http://')) + { + $item->galleryType = 'flickr'; + $item->galleryValue = JString::substr($item->gallery, 9); + $item->galleryValue = JString::substr($item->galleryValue, 0, -10); + } + else + { + $item->galleryType = 'server'; + $item->galleryValue = ''; + } + + $params->set('galleries_rootfolder', 'media/k2/galleries'); + $params->set('thb_width', '150'); + $params->set('thb_height', '120'); + $params->set('enabledownload', '0'); + $item->text = $item->gallery; + if (K2_JVERSION == '15') + { + $dispatcher->trigger('onPrepareContent', array(&$item, &$params, null)); + } + else + { + $dispatcher->trigger('onContentPrepare', array('com_k2.'.$view, &$item, &$params, null)); + } + $item->gallery = $item->text; + + if (!$embedVideo) + { + $params->set('vfolder', 'media/k2/videos'); + $params->set('afolder', 'media/k2/audio'); + if (JString::strpos($item->video, 'remote}')) + { + preg_match("#}(.*?){/#s", $item->video, $matches); + if (JString::substr($matches[1], 0, 7) != 'http://') + $item->video = str_replace($matches[1], JURI::root().$matches[1], $item->video); + } + $item->text = $item->video; + + if (K2_JVERSION == '15') + { + $dispatcher->trigger('onPrepareContent', array(&$item, &$params, null)); + } + else + { + $dispatcher->trigger('onContentPrepare', array('com_k2.'.$view, &$item, &$params, null)); + } + + $item->video = $item->text; + } + else + { + // no nothing + } + + if (isset($item->created_by)) + { + $author = JUser::getInstance($item->created_by); + $item->author = $author->name; + } + else + { + $item->author = $user->name; + } + if (isset($item->modified_by)) + { + $moderator = JUser::getInstance($item->modified_by); + $item->moderator = $moderator->name; + } + + if ($item->id) + { + $active = $item->created_by; + } + else + { + $active = $user->id; + } + $lists['authors'] = JHTML::_('list.users', 'created_by', $active, false); + + $categories_option[] = JHTML::_('select.option', 0, JText::_('K2_SELECT_CATEGORY')); + $categories = $categoriesModel->categoriesTree(NUll, true, false); + if ($mainframe->isSite()) + { + JLoader::register('K2HelperPermissions', JPATH_SITE.DS.'components'.DS.'com_k2'.DS.'helpers'.DS.'permissions.php'); + if (($task == 'add' || $task == 'edit') && !K2HelperPermissions::canAddToAll()) + { + for ($i = 0; $i < sizeof($categories); $i++) + { + if (!K2HelperPermissions::canAddItem($categories[$i]->value) && $task == 'add') + { + $categories[$i]->disable = true; + } + if (!K2HelperPermissions::canEditItem($item->created_by, $categories[$i]->value) && $task == 'edit') + { + $categories[$i]->disable = true; + } + } + } + } + $categories_options = @array_merge($categories_option, $categories); + $lists['categories'] = JHTML::_('select.genericlist', $categories_options, 'catid', '', 'value', 'text', $item->catid); + + JTable::addIncludePath(JPATH_COMPONENT.DS.'tables'); + $category = JTable::getInstance('K2Category', 'Table'); + $category->load($item->catid); + + $extraFieldModel = K2Model::getInstance('ExtraField', 'K2Model'); + if ($category->id) + { + $extraFields = $extraFieldModel->getExtraFieldsByGroup($category->extraFieldsGroup); + } + else + { + $extraFields = NULL; + } + + for ($i = 0; $i < sizeof($extraFields); $i++) + { + $extraFields[$i]->element = $extraFieldModel->renderExtraField($extraFields[$i], $item->id); + } + + if ($item->id) + { + $item->attachments = $model->getAttachments($item->id); + $rating = $model->getRating(); + if (is_null($rating)) + { + $item->ratingSum = 0; + $item->ratingCount = 0; + } + else + { + $item->ratingSum = (int)$rating->rating_sum; + $item->ratingCount = (int)$rating->rating_count; + } + } + else + { + $item->attachments = NULL; + $item->ratingSum = 0; + $item->ratingCount = 0; + } + + if ($user->gid < 24 && $params->get('lockTags')) + { + $params->set('taggingSystem', 0); + } + + $tags = $model->getAvailableTags($item->id); + $lists['tags'] = JHTML::_('select.genericlist', $tags, 'tags', 'multiple="multiple" size="10" ', 'id', 'name'); + + if (isset($item->id)) + { + $item->tags = $model->getCurrentTags($item->id); + $lists['selectedTags'] = JHTML::_('select.genericlist', $item->tags, 'selectedTags[]', 'multiple="multiple" size="10" ', 'id', 'name'); + } + else + { + $lists['selectedTags'] = ''; + } + + $lists['metadata'] = class_exists('JParameter') ? new JParameter($item->metadata) : new JRegistry($item->metadata); + + $date = JFactory::getDate($item->modified); + $timestamp = '?t='.$date->toUnix(); + + if (JFile::exists(JPATH_SITE.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$item->id).'_L.jpg')) + { + $item->image = JURI::root().'media/k2/items/cache/'.md5("Image".$item->id).'_L.jpg'.$timestamp; + } + + if (JFile::exists(JPATH_SITE.DS.'media'.DS.'k2'.DS.'items'.DS.'cache'.DS.md5("Image".$item->id).'_S.jpg')) + { + $item->thumb = JURI::root().'media/k2/items/cache/'.md5("Image".$item->id).'_S.jpg'.$timestamp; + } + + JPluginHelper::importPlugin('k2'); + $dispatcher = JDispatcher::getInstance(); + + $K2PluginsItemContent = $dispatcher->trigger('onRenderAdminForm', array(&$item, 'item', 'content')); + $this->assignRef('K2PluginsItemContent', $K2PluginsItemContent); + + $K2PluginsItemImage = $dispatcher->trigger('onRenderAdminForm', array(&$item, 'item', 'image')); + $this->assignRef('K2PluginsItemImage', $K2PluginsItemImage); + + $K2PluginsItemGallery = $dispatcher->trigger('onRenderAdminForm', array(&$item, 'item', 'gallery')); + $this->assignRef('K2PluginsItemGallery', $K2PluginsItemGallery); + + $K2PluginsItemVideo = $dispatcher->trigger('onRenderAdminForm', array(&$item, 'item', 'video')); + $this->assignRef('K2PluginsItemVideo', $K2PluginsItemVideo); + + $K2PluginsItemExtraFields = $dispatcher->trigger('onRenderAdminForm', array(&$item, 'item', 'extra-fields')); + $this->assignRef('K2PluginsItemExtraFields', $K2PluginsItemExtraFields); + + $K2PluginsItemAttachments = $dispatcher->trigger('onRenderAdminForm', array(&$item, 'item', 'attachments')); + $this->assignRef('K2PluginsItemAttachments', $K2PluginsItemAttachments); + + $K2PluginsItemOther = $dispatcher->trigger('onRenderAdminForm', array(&$item, 'item', 'other')); + $this->assignRef('K2PluginsItemOther', $K2PluginsItemOther); + + if (version_compare(JVERSION, '1.6.0', 'ge')) + { + jimport('joomla.form.form'); + $form = JForm::getInstance('itemForm', JPATH_COMPONENT_ADMINISTRATOR.DS.'models'.DS.'item.xml'); + $values = array('params' => json_decode($item->params)); + $form->bind($values); + } + else + { + $form = new JParameter('', JPATH_COMPONENT_ADMINISTRATOR.DS.'models'.DS.'item.xml'); + $form->loadINI($item->params); + } + $this->assignRef('form', $form); + + $nullDate = $db->getNullDate(); + $this->assignRef('nullDate', $nullDate); + + $this->assignRef('extraFields', $extraFields); + $this->assignRef('options', $options); + $this->assignRef('row', $item); + $this->assignRef('lists', $lists); + $this->assignRef('params', $params); + $this->assignRef('user', $user); + (JRequest::getInt('cid')) ? $title = JText::_('K2_EDIT_ITEM') : $title = JText::_('K2_ADD_ITEM'); + $this->assignRef('title', $title); + $this->assignRef('mainframe', $mainframe); + if ($mainframe->isAdmin()) + { + $this->params->set('showImageTab', true); + $this->params->set('showImageGalleryTab', true); + $this->params->set('showVideoTab', true); + $this->params->set('showExtraFieldsTab', true); + $this->params->set('showAttachmentsTab', true); + $this->params->set('showK2Plugins', true); + JToolBarHelper::title($title, 'k2.png'); + JToolBarHelper::save(); + JToolBarHelper::custom('saveAndNew', 'save.png', 'save_f2.png', 'K2_SAVE_AND_NEW', false); + JToolBarHelper::apply(); + JToolBarHelper::cancel(); + } + // ACE ACL integration + $definedConstants = get_defined_constants(); + if (!empty($definedConstants['ACEACL']) && AceaclApi::authorize('permissions', 'com_aceacl')) + { + $aceAclFlag = true; + } + else + { + $aceAclFlag = false; + } + $this->assignRef('aceAclFlag', $aceAclFlag); + + // SIG PRO v3 integration + if (JPluginHelper::isEnabled('k2', 'jw_sigpro')) + { + $sigPro = true; + $sigProFolder = ($this->row->id) ? $this->row->id : uniqid(); + $this->assignRef('sigProFolder', $sigProFolder); + } + else + { + $sigPro = false; + } + $this->assignRef('sigPro', $sigPro); + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/views/items/tmpl/default.php b/administrator/components/com_k2/views/items/tmpl/default.php new file mode 100644 index 0000000..e213c69 --- /dev/null +++ b/administrator/components/com_k2/views/items/tmpl/default.php @@ -0,0 +1,204 @@ +addScriptDeclaration(" + \$K2(document).ready(function(){ + \$K2('#K2ImportContentButton').click(function(event){ + var answer = confirm('".JText::_('K2_WARNING_YOU_ARE_ABOUT_TO_IMPORT_ALL_SECTIONS_CATEGORIES_AND_ARTICLES_FROM_JOOMLAS_CORE_CONTENT_COMPONENT_COM_CONTENT_INTO_K2_IF_THIS_IS_THE_FIRST_TIME_YOU_IMPORT_CONTENT_TO_K2_AND_YOUR_SITE_HAS_MORE_THAN_A_FEW_THOUSAND_ARTICLES_THE_PROCESS_MAY_TAKE_A_FEW_MINUTES_IF_YOU_HAVE_EXECUTED_THIS_OPERATION_BEFORE_DUPLICATE_CONTENT_MAY_BE_PRODUCED', true)."'); + if(!answer){ + event.preventDefault(); + } + }); + }); +"); + +?> + +
    + + + + + + +
    + + + + + lists['trash']; ?> + lists['featured']; ?> + lists['categories']; ?> + lists['tag'])): ?> + lists['tag']; ?> + + lists['authors']; ?> lists['state']; ?> + lists['language'])): ?> + lists['language']; ?> + + filters as $filter):?> + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + lists['language'])): ?> + + + + columns as $column):?> + + + + + + + + + + + rows as $key => $row): ?> + filter_featured!='1') echo ' sortable-group-id="'.$row->catid.'"'; ?>> + + + + + + + + + + + + + + + + + + + + + lists['language'])): ?> + + + + columns as $column):?> + + + + + +
    + filter_featured=='1'): ?> + ', 'i.featured_ordering', @$this->lists['order_Dir'], @$this->lists['order'], null, 'asc', 'K2_FEATURED_ORDER'); ?> + + ', 'i.ordering', @$this->lists['order_Dir'], @$this->lists['order'], null, 'asc', 'K2_ORDER'); ?> + + # + + lists['order_Dir'], @$this->lists['order']); ?> lists['order_Dir'], @$this->lists['order']); ?> lists['order_Dir'], @$this->lists['order']); ?> + filter_featured=='1'): ?> + lists['order_Dir'], @$this->lists['order']); ?> + ordering) {echo JHTML::_('grid.order', $this->rows, 'filesave.png','savefeaturedorder');} ?> + + lists['order_Dir'], @$this->lists['order']); ?> + ordering) {echo JHTML::_('grid.order', $this->rows);} ?> + + lists['order_Dir'], @$this->lists['order']); ?> lists['order_Dir'], @$this->lists['order']); ?> lists['order_Dir'], @$this->lists['order']); ?> lists['order_Dir'], @$this->lists['order']); ?> lists['order_Dir'], @$this->lists['order']); ?> lists['order_Dir'], @$this->lists['order']); ?> lists['order_Dir'], @$this->lists['order']); ?> lists['order_Dir'], @$this->lists['order']); ?> lists['order_Dir'], @$this->lists['order']); ?> label, $column->property, @$this->lists['order_Dir'], @$this->lists['order']); ?>
    + +
    + page->getLimitBox(); ?> +
    + + page->getListFooter(); ?> +
    + canChange): ?> + + + + + + + table->isCheckedOut($this->user->get('id'), $row->checked_out)): ?> + title; ?> + + filter_trash): ?> + title; ?> + + title; ?> + + + featuredStatus; ?>status; ?> + filter_featured=='1'): ?> + page->orderUpIcon($key, true, 'featuredorderup', 'K2_MOVE_UP', $this->ordering); ?> page->orderDownIcon($key, count($this->rows), true, 'featuredorderdown', 'K2_MOVE_DOWN', $this->ordering); ?> + ordering) ? '' : 'disabled="disabled"' ?> class="text_area k2OrderBox" /> + + page->orderUpIcon($key, ($row->catid == @$this->rows[$key-1]->catid), 'orderup', 'K2_MOVE_UP', $this->ordering); ?> page->orderDownIcon($key, count($this->rows), ($row->catid == @$this->rows[$key+1]->catid), 'orderdown', 'K2_MOVE_DOWN', $this->ordering); ?> + ordering)? '' : 'disabled="disabled"' ?> class="text_area k2OrderBox" /> + + category; ?> + user->gid>23): ?> + author; ?> + + author; ?> + + + user->gid>23): ?> + moderator; ?> + + moderator; ?> + + filter_trash || K2_JVERSION != '15')? $row->groupname:JHTML::_('grid.access', $row, $key); ?>created , $this->dateFormat); ?>modified == $this->nullDate) ? JText::_('K2_NEVER') : JHTML::_('date', $row->modified , $this->dateFormat); ?>hits ?> + id).'_XL.jpg')): ?> + id).'_XL.jpg'; ?>" title="" class="modal"> + + + + <?php echo JText::_('K2_PREVIEW_IMAGE'); ?> + + + + language; ?>id; ?>class){ echo 'class="'.$column->class.'"';}?>> + property; echo $row->$property; ?> +
    + + + + + + + +
    diff --git a/administrator/components/com_k2/views/items/tmpl/element.php b/administrator/components/com_k2/views/items/tmpl/element.php new file mode 100644 index 0000000..f962c80 --- /dev/null +++ b/administrator/components/com_k2/views/items/tmpl/element.php @@ -0,0 +1,82 @@ + +
    +

    + + + + + +
    + + + + + + lists['trash']; ?> + lists['featured']; ?> | + lists['categories']; ?> + lists['tag'])): ?> + lists['tag']; ?> + + lists['authors']; ?> + lists['state']; ?> + lists['language'])): ?> + lists['language']; ?> + +
    + + + + + + + + + + + + + + rows as $key => $row): ?> + + + + + + + + + + + + + + + + +
    lists['order_Dir'], @$this->lists['order']); ?>lists['order_Dir'], @$this->lists['order']); ?>lists['order_Dir'], @$this->lists['order']); ?>lists['order_Dir'], @$this->lists['order']); ?>lists['order_Dir'], @$this->lists['order']); ?>lists['order_Dir'], @$this->lists['order']); ?>
    title); ?>', '');">title; ?>category; ?>author; ?>groupname; ?>created; ?>id; ?>
    + +
    + page->getLimitBox(); ?> +
    + + page->getListFooter(); ?> +
    + + + + + + +
    \ No newline at end of file diff --git a/administrator/components/com_k2/views/items/tmpl/move.php b/administrator/components/com_k2/views/items/tmpl/move.php new file mode 100644 index 0000000..22f4b32 --- /dev/null +++ b/administrator/components/com_k2/views/items/tmpl/move.php @@ -0,0 +1,46 @@ +addScriptDeclaration(" + Joomla.submitbutton = function(pressbutton) { + if (pressbutton == 'cancel') { + submitform( pressbutton ); + return; + } + if (\$K2.trim(\$K2('#category').val()) == '') { + alert( '".JText::_('K2_YOU_MUST_SELECT_A_TARGET_CATEGORY', true)."' ); + } else { + submitform( pressbutton ); + } + } +"); + +?> + +
    +
    + + lists['categories']; ?> +
    +
    + (rows); ?>) +
      + rows as $row): ?> +
    1. title; ?>
    2. + +
    +
    + + + +
    diff --git a/administrator/components/com_k2/views/items/view.html.php b/administrator/components/com_k2/views/items/view.html.php new file mode 100644 index 0000000..8a6777f --- /dev/null +++ b/administrator/components/com_k2/views/items/view.html.php @@ -0,0 +1,352 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', 'i.id', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', 'DESC', 'word'); + $filter_trash = $mainframe->getUserStateFromRequest($option.$view.'filter_trash', 'filter_trash', 0, 'int'); + $filter_featured = $mainframe->getUserStateFromRequest($option.$view.'filter_featured', 'filter_featured', -1, 'int'); + $filter_category = $mainframe->getUserStateFromRequest($option.$view.'filter_category', 'filter_category', 0, 'int'); + $filter_author = $mainframe->getUserStateFromRequest($option.$view.'filter_author', 'filter_author', 0, 'int'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', -1, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + $tag = $mainframe->getUserStateFromRequest($option.$view.'tag', 'tag', 0, 'int'); + $language = $mainframe->getUserStateFromRequest($option.$view.'language', 'language', '', 'string'); + $params = JComponentHelper::getParams('com_k2'); + + $db = JFactory::getDBO(); + $nullDate = $db->getNullDate(); + $this->assignRef('nullDate', $nullDate); + + $model = $this->getModel(); + $total = $model->getTotal(); + if ($limitstart > $total - $limit) + { + $limitstart = max(0, (int)(ceil($total / $limit) - 1) * $limit); + JRequest::setVar('limitstart', $limitstart); + } + $items = $model->getData(); + + if (K2_JVERSION != '15') + { + $langs = JLanguageHelper::getLanguages(); + $langsMapping = array(); + $langsMapping['*'] = JText::_('K2_ALL'); + foreach ($langs as $lang) + { + $langsMapping[$lang->lang_code] = $lang->title; + } + } + + foreach ($items as $key => $item) + { + if (K2_JVERSION != '15') + { + $item->status = JHtml::_('jgrid.published', $item->published, $key, '', ($filter_trash == 0), 'cb', $item->publish_up, $item->publish_down); + $states = array( + 1 => array( + 'featured', + 'K2_FEATURED', + 'K2_REMOVE_FEATURED_FLAG', + 'K2_FEATURED', + false, + 'publish', + 'publish' + ), + 0 => array( + 'featured', + 'K2_NOT_FEATURED', + 'K2_FLAG_AS_FEATURED', + 'K2_NOT_FEATURED', + false, + 'unpublish', + 'unpublish' + ), + ); + $item->featuredStatus = JHtml::_('jgrid.state', $states, $item->featured, $key, '', $filter_trash == 0); + $item->canChange = $user->authorise('core.edit.state', 'com_k2.item.'.$item->id); + $item->language = $item->language ? $item->language : '*'; + if (isset($langsMapping)) + { + $item->language = $langsMapping[$item->language]; + } + } + else + { + $now = JFactory::getDate(); + $config = JFactory::getConfig(); + $publish_up = JFactory::getDate($item->publish_up); + $publish_down = JFactory::getDate($item->publish_down); + $publish_up->setOffset($config->getValue('config.offset')); + $publish_down->setOffset($config->getValue('config.offset')); + $img = 'tick.png'; + if ($now->toUnix() <= $publish_up->toUnix() && $item->published == 1) + { + $img = 'publish_y.png'; + } + else if (($now->toUnix() <= $publish_down->toUnix() || $item->publish_down == $nullDate) && $item->published == 1) + { + $img = 'tick.png'; + } + else if ($now->toUnix() > $publish_down->toUnix() && $item->published == 1) + { + $img = 'publish_r.png'; + } + $item->status = JHTML::_('grid.published', $item, $key, $img); + if ($filter_trash) + { + $item->status = strip_tags($item->status, ''); + } + + $item->featuredStatus = ''; + if (!$filter_trash) + { + $tmpTitle = $item->featured ? JText::_('K2_REMOVE_FEATURED_FLAG') : JText::_('K2_FLAG_AS_FEATURED'); + $item->featuredStatus .= ''; + + } + $item->state = $item->published; + $item->published = $item->featured; + $item->featuredStatus .= strip_tags(JHTML::_('grid.published', $item, $key), ''); + $item->published = $item->state; + if (!$filter_trash) + { + $item->featuredStatus .= ''; + } + + } + } + $this->assignRef('rows', $items); + + $lists = array(); + $lists['search'] = $search; + + if (!$filter_order) + { + $filter_order = 'category'; + } + $lists['order_Dir'] = $filter_order_Dir; + $lists['order'] = $filter_order; + + $filter_trash_options[] = JHTML::_('select.option', 0, JText::_('K2_CURRENT')); + $filter_trash_options[] = JHTML::_('select.option', 1, JText::_('K2_TRASHED')); + $lists['trash'] = JHTML::_('select.genericlist', $filter_trash_options, 'filter_trash', '', 'value', 'text', $filter_trash); + + require_once JPATH_ADMINISTRATOR.'/components/com_k2/models/categories.php'; + $categoriesModel = K2Model::getInstance('Categories', 'K2Model'); + $categories_option[] = JHTML::_('select.option', 0, JText::_('K2_SELECT_CATEGORY')); + $categories = $categoriesModel->categoriesTree(NULL, true, false); + $categories_options = @array_merge($categories_option, $categories); + $lists['categories'] = JHTML::_('select.genericlist', $categories_options, 'filter_category', '', 'value', 'text', $filter_category); + + $authors = $model->getItemsAuthors(); + $options = array(); + $options[] = JHTML::_('select.option', 0, '- '.JText::_('K2_NO_USER').' -'); + foreach ($authors as $author) + { + $name = $author->name; + if ($author->block) + { + $name .= ' ['.JText::_('K2_USER_DISABLED').']'; + } + $options[] = JHTML::_('select.option', $author->id, $name); + } + $lists['authors'] = JHTML::_('select.genericlist', $options, 'filter_author', '', 'value', 'text', $filter_author); + + $filter_state_options[] = JHTML::_('select.option', -1, JText::_('K2_SELECT_PUBLISHING_STATE')); + $filter_state_options[] = JHTML::_('select.option', 1, JText::_('K2_PUBLISHED')); + $filter_state_options[] = JHTML::_('select.option', 0, JText::_('K2_UNPUBLISHED')); + $lists['state'] = JHTML::_('select.genericlist', $filter_state_options, 'filter_state', '', 'value', 'text', $filter_state); + + $filter_featured_options[] = JHTML::_('select.option', -1, JText::_('K2_SELECT_FEATURED_STATE')); + $filter_featured_options[] = JHTML::_('select.option', 1, JText::_('K2_FEATURED')); + $filter_featured_options[] = JHTML::_('select.option', 0, JText::_('K2_NOT_FEATURED')); + $lists['featured'] = JHTML::_('select.genericlist', $filter_featured_options, 'filter_featured', '', 'value', 'text', $filter_featured); + + if ($params->get('showTagFilter')) + { + $tagsModel = K2Model::getInstance('Tags', 'K2Model'); + $options = $tagsModel->getFilter(); + $option = new JObject(); + $option->id = 0; + $option->name = JText::_('K2_SELECT_TAG'); + array_unshift($options, $option); + $lists['tag'] = JHTML::_('select.genericlist', $options, 'tag', '', 'id', 'name', $tag); + } + + if (version_compare(JVERSION, '1.6.0', 'ge')) + { + $languages = JHTML::_('contentlanguage.existing', true, true); + array_unshift($languages, JHTML::_('select.option', '', JText::_('K2_SELECT_LANGUAGE'))); + $lists['language'] = JHTML::_('select.genericlist', $languages, 'language', '', 'value', 'text', $language); + } + + $this->assignRef('lists', $lists); + + jimport('joomla.html.pagination'); + + $pageNav = new JPagination($total, $limitstart, $limit); + $this->assignRef('page', $pageNav); + + $filters = array(); + $columns = array(); + $dispatcher = JDispatcher::getInstance(); + JPluginHelper::importPlugin('k2'); + $dispatcher->trigger('onK2BeforeAssignFilters', array(&$filters)); + $this->assignRef('filters', $filters); + $dispatcher->trigger('onK2BeforeAssignColumns', array(&$columns)); + $this->assignRef('columns', $columns); + + JToolBarHelper::title(JText::_('K2_ITEMS'), 'k2.png'); + if ($filter_trash == 1) + { + JToolBarHelper::custom('restore', 'publish.png', 'publish_f2.png', 'K2_RESTORE', true); + JToolBarHelper::deleteList('K2_ARE_YOU_SURE_YOU_WANT_TO_DELETE_SELECTED_ITEMS', 'remove', 'K2_DELETE'); + } + else + { + + $params = JComponentHelper::getParams('com_k2'); + $toolbar = JToolBar::getInstance('toolbar'); + + K2_JVERSION == '30' ? JToolBarHelper::custom('featured', 'featured.png', 'featured_f2.png', 'K2_TOGGLE_FEATURED_STATE', true) : JToolBarHelper::custom('featured', 'default.png', 'default_f2.png', 'K2_TOGGLE_FEATURED_STATE', true); + JToolBarHelper::publishList(); + JToolBarHelper::unpublishList(); + JToolBarHelper::custom('move', 'move.png', 'move_f2.png', 'K2_MOVE', true); + JToolBarHelper::custom('copy', 'copy.png', 'copy_f2.png', 'K2_COPY', true); + JToolBarHelper::editList(); + JToolBarHelper::addNew(); + JToolBarHelper::trash('trash'); + + } + + $toolbar = JToolBar::getInstance('toolbar'); + if (K2_JVERSION != '15') + { + JToolBarHelper::preferences('com_k2', 550, 875, 'K2_PARAMETERS'); + } + else + { + $toolbar->appendButton('Popup', 'config', 'K2_PARAMETERS', 'index.php?option=com_k2&view=settings'); + } + + // Import Joomla! content button + if ($user->gid > 23 && !$params->get('hideImportButton')) + { + $buttonUrl = JURI::base().'index.php?option=com_k2&view=items&task=import'; + $buttonText = JText::_('K2_IMPORT_JOOMLA_CONTENT'); + if (K2_JVERSION == '30') + { + $button = ''.$buttonText.''; + } + else + { + $button = ''.$buttonText.''; + } + $toolbar->appendButton('Custom', $button); + } + + $this->loadHelper('html'); + K2HelperHTML::subMenu(); + + $template = $mainframe->getTemplate(); + $this->assignRef('template', $template); + $this->assignRef('filter_featured', $filter_featured); + $this->assignRef('filter_trash', $filter_trash); + $this->assignRef('user', $user); + if (K2_JVERSION != '15') + { + $dateFormat = JText::_('K2_J16_DATE_FORMAT'); + } + else + { + $dateFormat = JText::_('K2_DATE_FORMAT'); + } + $this->assignRef('dateFormat', $dateFormat); + + $ordering = (($this->lists['order'] == 'i.ordering' || $this->lists['order'] == 'category' || ($this->filter_featured > 0 && $this->lists['order'] == 'i.featured_ordering')) && (!$this->filter_trash)); + $this->assignRef('ordering', $ordering); + + JTable::addIncludePath(JPATH_COMPONENT.DS.'tables'); + $table = JTable::getInstance('K2Item', 'Table'); + $this->assignRef('table', $table); + + // Joomla! 3.0 drag-n-drop sorting variables + if (K2_JVERSION == '30') + { + if ($ordering) + { + $action = $this->filter_featured == 1 ? 'savefeaturedorder' : 'saveorder'; + JHtml::_('sortablelist.sortable', 'k2ItemsList', 'adminForm', strtolower($this->lists['order_Dir']), 'index.php?option=com_k2&view=items&task='.$action.'&format=raw'); + } + $document = JFactory::getDocument(); + $document->addScriptDeclaration(' + Joomla.orderTable = function() { + table = document.getElementById("sortTable"); + direction = document.getElementById("directionTable"); + order = table.options[table.selectedIndex].value; + if (order != \''.$this->lists['order'].'\') { + dirn = \'asc\'; + } else { + dirn = direction.options[direction.selectedIndex].value; + } + Joomla.tableOrdering(order, dirn, ""); + }'); + } + + parent::display($tpl); + } + + function move() + { + + $mainframe = JFactory::getApplication(); + JTable::addIncludePath(JPATH_COMPONENT.DS.'tables'); + $cid = JRequest::getVar('cid'); + + foreach ($cid as $id) + { + $row = JTable::getInstance('K2Item', 'Table'); + $row->load($id); + $rows[] = $row; + } + + $categoriesModel = K2Model::getInstance('Categories', 'K2Model'); + $categories = $categoriesModel->categoriesTree(null, true, false); + $lists['categories'] = JHTML::_('select.genericlist', $categories, 'category', 'class="inputbox" size="8"', 'value', 'text'); + + $this->assignRef('rows', $rows); + $this->assignRef('lists', $lists); + + JToolBarHelper::title(JText::_('K2_MOVE_ITEMS'), 'k2.png'); + + JToolBarHelper::custom('saveMove', 'save.png', 'save_f2.png', 'K2_SAVE', false); + JToolBarHelper::cancel(); + + parent::display(); + } + +} diff --git a/administrator/components/com_k2/views/media/tmpl/default.php b/administrator/components/com_k2/views/media/tmpl/default.php new file mode 100644 index 0000000..d153824 --- /dev/null +++ b/administrator/components/com_k2/views/media/tmpl/default.php @@ -0,0 +1,31 @@ + + +
    diff --git a/administrator/components/com_k2/views/media/view.html.php b/administrator/components/com_k2/views/media/view.html.php new file mode 100644 index 0000000..823850b --- /dev/null +++ b/administrator/components/com_k2/views/media/view.html.php @@ -0,0 +1,62 @@ +addStyleSheet('//ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/smoothness/jquery-ui.css'); + $document->addStyleSheet(JURI::root(true).'/media/k2/assets/css/theme.css?v=2.6.7'); + $document->addStyleSheet(JURI::root(true).'/media/k2/assets/css/elfinder.min.css?v=2.6.7'); + $type = JRequest::getCmd('type'); + $fieldID = JRequest::getCmd('fieldID'); + if ($type == 'video') + { + $mimes = "'video','audio'"; + } + elseif ($type == 'image') + { + $mimes = "'image'"; + } + else + { + $mimes = ''; + } + $this->assignRef('mimes', $mimes); + $this->assignRef('type', $type); + $this->assignRef('fieldID', $fieldID); + if ($mainframe->isAdmin()) + { + $toolbar = JToolBar::getInstance('toolbar'); + if (K2_JVERSION != '15') + { + JToolBarHelper::preferences('com_k2', 550, 875, 'K2_PARAMETERS'); + } + else + { + $toolbar->appendButton('Popup', 'config', 'K2_PARAMETERS', 'index.php?option=com_k2&view=settings'); + } + JToolBarHelper::title(JText::_('K2_MEDIA_MANAGER'), 'k2.png'); + $this->loadHelper('html'); + K2HelperHTML::subMenu(); + } + parent::display($tpl); + + } + +} diff --git a/administrator/components/com_k2/views/settings/tmpl/default.php b/administrator/components/com_k2/views/settings/tmpl/default.php new file mode 100644 index 0000000..ba0ffc0 --- /dev/null +++ b/administrator/components/com_k2/views/settings/tmpl/default.php @@ -0,0 +1,37 @@ + + +
    +
    +
    + + +
    +
    + +
    +
    +
    + pane->startPane('settings'); ?> + params->getGroups() as $group=>$value): ?> + pane->startPanel(JText::_($group), $group.'-tab'); ?> + params->render('params', $group); ?> + pane->endPanel(); ?> + + pane->endPane(); ?> + + + + + +
    diff --git a/administrator/components/com_k2/views/settings/view.html.php b/administrator/components/com_k2/views/settings/view.html.php new file mode 100644 index 0000000..ac09817 --- /dev/null +++ b/administrator/components/com_k2/views/settings/view.html.php @@ -0,0 +1,29 @@ +getModel(); + $params = &$model->getParams(); + $this->assignRef('params', $params); + $pane = & JPane::getInstance('Tabs'); + $this->assignRef('pane', $pane); + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/views/tag/tmpl/default.php b/administrator/components/com_k2/views/tag/tmpl/default.php new file mode 100644 index 0000000..46a4999 --- /dev/null +++ b/administrator/components/com_k2/views/tag/tmpl/default.php @@ -0,0 +1,47 @@ +addScriptDeclaration(" + Joomla.submitbutton = function(pressbutton){ + if (pressbutton == 'cancel') { + submitform( pressbutton ); + return; + } + if (\$K2.trim(\$K2('#name').val())=='') { + alert( '".JText::_('K2_TAG_CANNOT_BE_EMPTY', true)."' ); + } else { + submitform( pressbutton ); + } + } +"); + +?> + +
    + + + + + + + + + +
    lists['published']; ?>
    + + + + + + +
    diff --git a/administrator/components/com_k2/views/tag/view.html.php b/administrator/components/com_k2/views/tag/view.html.php new file mode 100644 index 0000000..832497b --- /dev/null +++ b/administrator/components/com_k2/views/tag/view.html.php @@ -0,0 +1,41 @@ +getModel(); + $tag = $model->getData(); + JFilterOutput::objectHTMLSafe($tag); + if (!$tag->id) + $tag->published = 1; + $this->assignRef('row', $tag); + + $lists = array(); + $lists['published'] = JHTML::_('select.booleanlist', 'published', 'class="inputbox"', $tag->published); + $this->assignRef('lists', $lists); + (JRequest::getInt('cid')) ? $title = JText::_('K2_EDIT_TAG') : $title = JText::_('K2_ADD_TAG'); + JToolBarHelper::title($title, 'k2.png'); + JToolBarHelper::save(); + JToolBarHelper::apply(); + JToolBarHelper::cancel(); + + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/views/tags/tmpl/default.php b/administrator/components/com_k2/views/tags/tmpl/default.php new file mode 100644 index 0000000..b2d28ea --- /dev/null +++ b/administrator/components/com_k2/views/tags/tmpl/default.php @@ -0,0 +1,85 @@ +addScriptDeclaration(" + Joomla.submitbutton = function(pressbutton) { + if (pressbutton == 'remove') { + if (confirm('".JText::_('K2_ARE_YOU_SURE_YOU_WANT_TO_DELETE_SELECTED_TAGS', true)."')){ + submitform( pressbutton ); + } + } else { + submitform( pressbutton ); + } + } +"); + +?> + +
    + + + + + +
    + + + + + + lists['state']; ?> +
    + + + + + + + + + + + + + + + + + + rows as $key => $row): ?> + + + + + + + + + + +
    #lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>
    + +
    + page->getLimitBox(); ?> +
    + + page->getListFooter(); ?> +
    checked_out = 0; echo @JHTML::_('grid.checkedout', $row, $key ); ?>name; ?>status; ?>numOfItems; ?>id; ?>
    + + + + + + + +
    diff --git a/administrator/components/com_k2/views/tags/tmpl/element.php b/administrator/components/com_k2/views/tags/tmpl/element.php new file mode 100644 index 0000000..a9fe569 --- /dev/null +++ b/administrator/components/com_k2/views/tags/tmpl/element.php @@ -0,0 +1,66 @@ + +
    + + + + + +
    + + + + + + lists['state']; ?> +
    + + + + + + + + + + + rows as $key => $row): ?> + + + + + + + + + + + + + +
    lists['order_Dir'], @$this->lists['order'] ); ?> lists['order_Dir'], @$this->lists['order'] ); ?> lists['order_Dir'], @$this->lists['order'] ); ?>
    name); ?>', 'tag');">name; ?>status; ?>id; ?>
    + +
    + page->getLimitBox(); ?> +
    + + page->getListFooter(); ?> +
    + + + + + + + +
    \ No newline at end of file diff --git a/administrator/components/com_k2/views/tags/view.html.php b/administrator/components/com_k2/views/tags/view.html.php new file mode 100644 index 0000000..5729291 --- /dev/null +++ b/administrator/components/com_k2/views/tags/view.html.php @@ -0,0 +1,88 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', 'id', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', 'DESC', 'word'); + $filter_state = $mainframe->getUserStateFromRequest($option.$view.'filter_state', 'filter_state', -1, 'int'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + $model = $this->getModel(); + $total = $model->getTotal(); + $task = JRequest::getCmd('task'); + + if ($limitstart > $total - $limit) + { + $limitstart = max(0, (int)(ceil($total / $limit) - 1) * $limit); + JRequest::setVar('limitstart', $limitstart); + } + $tags = $model->getData(); + foreach ($tags as $key => $tag) + { + $tag->status = K2_JVERSION == '15' ? JHTML::_('grid.published', $tag, $key) : JHtml::_('jgrid.published', $tag->published, $key, '', $task != 'element'); + } + $this->assignRef('rows', $tags); + + jimport('joomla.html.pagination'); + $pageNav = new JPagination($total, $limitstart, $limit); + $this->assignRef('page', $pageNav); + + $lists = array(); + $lists['search'] = $search; + $lists['order_Dir'] = $filter_order_Dir; + $lists['order'] = $filter_order; + + $filter_state_options[] = JHTML::_('select.option', -1, JText::_('K2_SELECT_STATE')); + $filter_state_options[] = JHTML::_('select.option', 1, JText::_('K2_PUBLISHED')); + $filter_state_options[] = JHTML::_('select.option', 0, JText::_('K2_UNPUBLISHED')); + $lists['state'] = JHTML::_('select.genericlist', $filter_state_options, 'filter_state', '', 'value', 'text', $filter_state); + + $this->assignRef('lists', $lists); + + JToolBarHelper::title(JText::_('K2_TAGS'), 'k2.png'); + + JToolBarHelper::publishList(); + JToolBarHelper::unpublishList(); + JToolBarHelper::deleteList('', 'remove', 'K2_DELETE'); + JToolBarHelper::custom('removeOrphans', 'delete', 'delete', 'K2_DELETE_ORPHAN_TAGS', false); + JToolBarHelper::editList(); + JToolBarHelper::addNew(); + + if (K2_JVERSION != '15') + { + JToolBarHelper::preferences('com_k2', 550, 875, 'K2_PARAMETERS'); + } + else + { + $toolbar = JToolBar::getInstance('toolbar'); + $toolbar->appendButton('Popup', 'config', 'Parameters', 'index.php?option=com_k2&view=settings'); + } + + $this->loadHelper('html'); + K2HelperHTML::subMenu(); + + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/views/user/tmpl/default.php b/administrator/components/com_k2/views/user/tmpl/default.php new file mode 100644 index 0000000..84e7ef9 --- /dev/null +++ b/administrator/components/com_k2/views/user/tmpl/default.php @@ -0,0 +1,78 @@ + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    row->name; ?>
    lists['gender']; ?>
    lists['userGroup']; ?>
    +
    + editor; ?> +
    +
    +
    +
    + + row->image): ?> + <?php echo $this->row->name; ?> + + +
    + + K2Plugins))): ?> + K2Plugins as $K2Plugin): ?> + +
    + name; ?> + fields; ?> +
    + + + + + + + + + + + + +
    \ No newline at end of file diff --git a/administrator/components/com_k2/views/user/view.html.php b/administrator/components/com_k2/views/user/view.html.php new file mode 100644 index 0000000..af09f0c --- /dev/null +++ b/administrator/components/com_k2/views/user/view.html.php @@ -0,0 +1,80 @@ +getModel(); + $user = $model->getData(); + if (K2_JVERSION == '15') + { + JFilterOutput::objectHTMLSafe($user); + } + else + { + JFilterOutput::objectHTMLSafe($user, ENT_QUOTES, array('params', 'plugins')); + } + $joomlaUser = JUser::getInstance(JRequest::getInt('cid')); + + $user->name = $joomlaUser->name; + $user->userID = $joomlaUser->id; + $this->assignRef('row', $user); + + $wysiwyg = JFactory::getEditor(); + $editor = $wysiwyg->display('description', $user->description, '480px', '250px', '', '', false); + $this->assignRef('editor', $editor); + + $lists = array(); + $genderOptions[] = JHTML::_('select.option', 'm', JText::_('K2_MALE')); + $genderOptions[] = JHTML::_('select.option', 'f', JText::_('K2_FEMALE')); + $lists['gender'] = JHTML::_('select.radiolist', $genderOptions, 'gender', '', 'value', 'text', $user->gender); + + $userGroupOptions = $model->getUserGroups(); + $lists['userGroup'] = JHTML::_('select.genericlist', $userGroupOptions, 'group', 'class="inputbox"', 'id', 'name', $user->group); + + $this->assignRef('lists', $lists); + + $params = JComponentHelper::getParams('com_k2'); + $this->assignRef('params', $params); + + JPluginHelper::importPlugin('k2'); + $dispatcher = JDispatcher::getInstance(); + $K2Plugins = $dispatcher->trigger('onRenderAdminForm', array(&$user, 'user')); + $this->assignRef('K2Plugins', $K2Plugins); + + JToolBarHelper::title(JText::_('K2_USER'), 'k2.png'); + JToolBarHelper::save(); + JToolBarHelper::apply(); + JToolBarHelper::cancel(); + $toolbar = JToolBar::getInstance('toolbar'); + if (K2_JVERSION != '15') + { + $buttonUrl = JURI::base().'index.php?option=com_users&view=user&task=user.edit&id='.$user->userID; + } + else + { + $buttonUrl = JURI::base().'index.php?option=com_users&view=user&task=edit&cid[]='.$user->userID; + } + $buttonText = JText::_('K2_EDIT_JOOMLA_USER'); + $button = ''.$buttonText.''; + $toolbar->prependButton('Custom', $button); + + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/views/usergroup/tmpl/default.php b/administrator/components/com_k2/views/usergroup/tmpl/default.php new file mode 100644 index 0000000..78b7587 --- /dev/null +++ b/administrator/components/com_k2/views/usergroup/tmpl/default.php @@ -0,0 +1,101 @@ +addScriptDeclaration(" + Joomla.submitbutton = function(pressbutton){ + if (pressbutton == 'cancel') { + submitform( pressbutton ); + return; + } + if (\$K2.trim(\$K2('#name').val()) == '') { + alert( '".JText::_('K2_GROUP_NAME_CANNOT_BE_EMPTY', true)."' ); + } else { + submitform( pressbutton ); + } + } +"); + +?> + +
    +
    + + + + + +
    +
    + +
    +

    + + form->render('params'); ?> + +
    +
      + form->getFieldset('user-permissions') as $field): ?> +
    • + type=='header'): ?> +
      input; ?>
      + type=='Spacer'): ?> +
       
      +
      + +
      label; ?>
      +
      input; ?>
      +
      + +
    • + +
    +
    + +
    + +
    +

    +
    +
      +
    • +
      +
      + categories == 'all') echo ' checked="checked"'; ?> /> + + categories == 'none') echo ' checked="checked"'; ?> /> + + categories != 'all' && $this->categories != 'none') echo ' checked="checked"'; ?> /> + +
      +
      +
    • +
    • +
      +
      lists['categories']; ?>
      +
      +
    • +
    • +
      +
      lists['inheritance']; ?>
      +
      +
    • +
    +
    +
    + + + + + + +
    diff --git a/administrator/components/com_k2/views/usergroup/view.html.php b/administrator/components/com_k2/views/usergroup/view.html.php new file mode 100644 index 0000000..8b6c041 --- /dev/null +++ b/administrator/components/com_k2/views/usergroup/view.html.php @@ -0,0 +1,71 @@ +getModel(); + $userGroup = $model->getData(); + if (K2_JVERSION == '15') + { + JFilterOutput::objectHTMLSafe($userGroup); + } + else + { + JFilterOutput::objectHTMLSafe($userGroup, ENT_QUOTES, 'permissions'); + } + $this->assignRef('row', $userGroup); + + if (K2_JVERSION == '15') + { + $form = new JParameter('', JPATH_COMPONENT.DS.'models'.DS.'usergroup.xml'); + $form->loadINI($userGroup->permissions); + $appliedCategories = $form->get('categories'); + $inheritance = $form->get('inheritance'); + } + else + { + jimport('joomla.form.form'); + $form = JForm::getInstance('permissions', JPATH_COMPONENT_ADMINISTRATOR.DS.'models'.DS.'usergroup.xml'); + $values = array('params' => json_decode($userGroup->permissions)); + $form->bind($values); + $inheritance = isset($values['params']->inheritance) ? $values['params']->inheritance : 0; + $appliedCategories = isset($values['params']->categories) ? $values['params']->categories : ''; + } + $this->assignRef('form', $form); + $this->assignRef('categories', $appliedCategories); + + $lists = array(); + require_once JPATH_ADMINISTRATOR.'/components/com_k2/models/categories.php'; + $categoriesModel = K2Model::getInstance('Categories', 'K2Model'); + $categories = $categoriesModel->categoriesTree(NULL, true); + $categories_options = @array_merge($categories_option, $categories); + $lists['categories'] = JHTML::_('select.genericlist', $categories, 'params[categories][]', 'multiple="multiple" size="15"', 'value', 'text', $appliedCategories); + $lists['inheritance'] = JHTML::_('select.booleanlist', 'params[inheritance]', NULL, $inheritance); + $this->assignRef('lists', $lists); + (JRequest::getInt('cid')) ? $title = JText::_('K2_EDIT_USER_GROUP') : $title = JText::_('K2_ADD_USER_GROUP'); + JToolBarHelper::title($title, 'k2.png'); + JToolBarHelper::save(); + JToolBarHelper::apply(); + JToolBarHelper::cancel(); + + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/views/usergroups/tmpl/default.php b/administrator/components/com_k2/views/usergroups/tmpl/default.php new file mode 100644 index 0000000..31def2a --- /dev/null +++ b/administrator/components/com_k2/views/usergroups/tmpl/default.php @@ -0,0 +1,70 @@ +addScriptDeclaration(" + Joomla.submitbutton = function(pressbutton) { + if (pressbutton == 'remove') { + if (confirm('".JText::_('K2_ARE_YOU_SURE_YOU_WANT_TO_DELETE_SELECTED_GROUPS', true)."')){ + submitform( pressbutton ); + } + } else { + submitform( pressbutton ); + } + } +"); + +?> + +
    + + + + + + + + + + + + + + + + + rows as $key => $row): ?> + + + + + + + + + +
    #lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>
    + +
    + page->getLimitBox(); ?> +
    + + page->getListFooter(); ?> +
    checked_out = 0; echo @JHTML::_('grid.checkedout', $row, $key ); ?>name; ?>numOfUsers; ?>id; ?>
    + + + + + + + +
    diff --git a/administrator/components/com_k2/views/usergroups/view.html.php b/administrator/components/com_k2/views/usergroups/view.html.php new file mode 100644 index 0000000..6d858e8 --- /dev/null +++ b/administrator/components/com_k2/views/usergroups/view.html.php @@ -0,0 +1,74 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', '', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', '', 'word'); + + $model = $this->getModel(); + $total = $model->getTotal(); + if ($limitstart > $total - $limit) + { + $limitstart = max(0, (int)(ceil($total / $limit) - 1) * $limit); + JRequest::setVar('limitstart', $limitstart); + } + $userGroups = $model->getData(); + + $this->assignRef('rows', $userGroups); + + jimport('joomla.html.pagination'); + $pageNav = new JPagination($total, $limitstart, $limit); + $this->assignRef('page', $pageNav); + + $lists = array(); + + $lists['order_Dir'] = $filter_order_Dir; + $lists['order'] = $filter_order; + + $this->assignRef('lists', $lists); + + JToolBarHelper::title(JText::_('K2_USER_GROUPS'), 'k2.png'); + + JToolBarHelper::deleteList('', 'remove', 'K2_DELETE'); + JToolBarHelper::editList(); + JToolBarHelper::addNew(); + + if (K2_JVERSION != '15') + { + JToolBarHelper::preferences('com_k2', 550, 875, 'K2_PARAMETERS'); + } + else + { + $toolbar = JToolBar::getInstance('toolbar'); + $toolbar->appendButton('Popup', 'config', 'Parameters', 'index.php?option=com_k2&view=settings'); + } + + $this->loadHelper('html'); + K2HelperHTML::subMenu(); + + parent::display($tpl); + } + +} diff --git a/administrator/components/com_k2/views/users/tmpl/default.php b/administrator/components/com_k2/views/users/tmpl/default.php new file mode 100644 index 0000000..b862453 --- /dev/null +++ b/administrator/components/com_k2/views/users/tmpl/default.php @@ -0,0 +1,110 @@ +addScriptDeclaration(" + \$K2(document).ready(function(){ + \$K2('#K2ImportUsersButton').click(function(event){ + var answer = confirm('".JText::_('K2_WARNING_YOU_ARE_ABOUT_TO_IMPORT_JOOMLA_USERS_TO_K2_GENERATING_CORRESPONDING_K2_USER_GROUPS_IF_YOU_HAVE_EXECUTED_THIS_OPERATION_BEFORE_DUPLICATE_CONTENT_MAY_BE_PRODUCED', true)."'); + if (!answer){ + event.preventDefault(); + } + }); + }); +"); + +?> + +
    + + + + + +
    + + + + + + lists['filter_group_k2']; ?> + lists['filter_group']; ?> + lists['status']; ?> +
    + + + + + + + + + + + + + + + + + + + + + + + + + rows as $key => $row): ?> + + + + + + + + + + + + + + + + + +
    #lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>lists['order_Dir'], @$this->lists['order'] ); ?>
    + +
    + page->getLimitBox(); ?> +
    + + page->getListFooter(); ?> +
    checked_out = 0; echo JHTML::_('grid.id', $key, $row->id ); ?>name; ?>username; ?>loggedInStatus; ?>blockStatus; ?>usertype; ?>groupname; ?>email; ?>lvisit) ? JHTML::_('date', $row->lvisit , $this->dateFormat):JText::_('K2_NEVER'); ?> + ip): ?> + + ip; ?> + + + + block): ?> + × + + id; ?>
    + + + + + + + +
    \ No newline at end of file diff --git a/administrator/components/com_k2/views/users/tmpl/element.php b/administrator/components/com_k2/views/users/tmpl/element.php new file mode 100644 index 0000000..a5b52d2 --- /dev/null +++ b/administrator/components/com_k2/views/users/tmpl/element.php @@ -0,0 +1,107 @@ + + +
    +

    + + + + + +
    + + + + + + lists['filter_group_k2']; ?> lists['filter_group']; ?> lists['status']; ?> +
    + + + + + + + + + + + + + + + + + + + rows as $key => $row): ?> + + + + + + + + + + + +
    + + + lists['order_Dir'], @$this->lists['order'] ); ?> + + lists['order_Dir'], @$this->lists['order'] ); ?> + + lists['order_Dir'], @$this->lists['order'] ); ?> + + lists['order_Dir'], @$this->lists['order'] ); ?> + + lists['order_Dir'], @$this->lists['order'] ); ?> + + lists['order_Dir'], @$this->lists['order'] ); ?> +
    + +
    + page->getLimitBox(); ?> +
    + + page->getListFooter(); ?> +
    + + + name); ?>', 'id');">name; ?> + + username; ?> + + blockStatus; ?> + + usertype; ?> + + groupname; ?> + + id; ?> +
    + + isAdmin): ?> + + + + + + + + + +
    diff --git a/administrator/components/com_k2/views/users/tmpl/move.php b/administrator/components/com_k2/views/users/tmpl/move.php new file mode 100644 index 0000000..7d6150d --- /dev/null +++ b/administrator/components/com_k2/views/users/tmpl/move.php @@ -0,0 +1,39 @@ + + +
    +
    + + lists['group']; ?> +
    +
    + + lists['k2group']; ?> +
    +
    + (rows); ?>) +
      + rows as $row): ?> +
    1. + name; ?> + +
    2. + +
    +
    + + + + +
    diff --git a/administrator/components/com_k2/views/users/view.html.php b/administrator/components/com_k2/views/users/view.html.php new file mode 100644 index 0000000..ec6fea5 --- /dev/null +++ b/administrator/components/com_k2/views/users/view.html.php @@ -0,0 +1,282 @@ +getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int'); + $limitstart = $mainframe->getUserStateFromRequest($option.$view.'.limitstart', 'limitstart', 0, 'int'); + $filter_order = $mainframe->getUserStateFromRequest($option.$view.'filter_order', 'filter_order', 'juser.name', 'cmd'); + $filter_order_Dir = $mainframe->getUserStateFromRequest($option.$view.'filter_order_Dir', 'filter_order_Dir', '', 'word'); + $filter_status = $mainframe->getUserStateFromRequest($option.$view.'filter_status', 'filter_status', -1, 'int'); + $filter_group = $mainframe->getUserStateFromRequest($option.$view.'filter_group', 'filter_group', '', 'string'); + $filter_group_k2 = $mainframe->getUserStateFromRequest($option.$view.'filter_group_k2', 'filter_group_k2', '', 'string'); + $search = $mainframe->getUserStateFromRequest($option.$view.'search', 'search', '', 'string'); + $search = JString::strtolower($search); + K2Model::addIncludePath(JPATH_COMPONENT_ADMINISTRATOR.DS.'models'); + $model = K2Model::getInstance('Users', 'K2Model'); + $total = $model->getTotal(); + if ($limitstart > $total - $limit) + { + $limitstart = max(0, (int)(ceil($total / $limit) - 1) * $limit); + JRequest::setVar('limitstart', $limitstart); + } + $users = $model->getData(); + $task = JRequest::getCmd('task'); + for ($i = 0; $i < sizeof($users); $i++) + { + + $users[$i]->loggedin = $model->checkLogin($users[$i]->id); + $users[$i]->profileID = $model->hasProfile($users[$i]->id); + if ($users[$i]->profileID) + { + $db->setQuery("SELECT ip FROM #__k2_users WHERE id = ".$users[$i]->profileID); + $users[$i]->ip = $db->loadResult(); + } + else + { + $users[$i]->ip = ''; + } + + if ($users[$i]->lastvisitDate == "0000-00-00 00:00:00") + { + $users[$i]->lvisit = false; + } + else + { + $users[$i]->lvisit = $users[$i]->lastvisitDate; + } + $users[$i]->link = JRoute::_('index.php?option=com_k2&view=user&cid='.$users[$i]->id); + if (K2_JVERSION == '15') + { + $users[$i]->published = $users[$i]->loggedin; + $users[$i]->loggedInStatus = strip_tags(JHTML::_('grid.published', $users[$i], $i), ''); + $users[$i]->blockStatus = ''; + if ($users[$i]->block) + { + $users[$i]->blockStatus .= ''.JText::_('K2_ENABLED').''; + } + else + { + $users[$i]->blockStatus .= ''.JText::_('K2_DISABLED').''; + } + if ($task == 'element') + { + $users[$i]->blockStatus = strip_tags($users[$i]->blockStatus, ''); + } + } + else + { + $states = array(1 => array('', 'K2_LOGGED_IN', 'K2_LOGGED_IN', 'K2_LOGGED_IN', false, 'publish', 'publish'), 0 => array('', 'K2_NOT_LOGGED_IN', 'K2_NOT_LOGGED_IN', 'K2_NOT_LOGGED_IN', false, 'unpublish', 'unpublish'), ); + $users[$i]->loggedInStatus = JHtml::_('jgrid.state', $states, $users[$i]->loggedin, $i, '', false); + $states = array( + 0 => array('disable', 'K2_ENABLED', 'K2_DISABLE', 'K2_ENABLED', false, 'publish', 'publish'), + 1 => array('enable', 'K2_DISABLED', 'K2_ENABLE', 'K2_DISABLED', false, 'unpublish', 'unpublish')); + $users[$i]->blockStatus = JHtml::_('jgrid.state', $states, $users[$i]->block, $i, '', $task != 'element'); + + } + + } + + $this->assignRef('rows', $users); + + jimport('joomla.html.pagination'); + $pageNav = new JPagination($total, $limitstart, $limit); + $this->assignRef('page', $pageNav); + + $lists = array(); + $lists['search'] = $search; + $lists['order_Dir'] = $filter_order_Dir; + $lists['order'] = $filter_order; + + $filter_status_options[] = JHTML::_('select.option', -1, JText::_('K2_SELECT_STATE')); + $filter_status_options[] = JHTML::_('select.option', 0, JText::_('K2_ENABLED')); + $filter_status_options[] = JHTML::_('select.option', 1, JText::_('K2_BLOCKED')); + $lists['status'] = JHTML::_('select.genericlist', $filter_status_options, 'filter_status', '', 'value', 'text', $filter_status); + + $userGroups = $model->getUserGroups(); + $groups[] = JHTML::_('select.option', '0', JText::_('K2_SELECT_JOOMLA_GROUP')); + + foreach ($userGroups as $userGroup) + { + $groups[] = JHTML::_('select.option', $userGroup->value, $userGroup->text); + } + + $lists['filter_group'] = JHTML::_('select.genericlist', $groups, 'filter_group', '', 'value', 'text', $filter_group); + + $K2userGroups = $model->getUserGroups('k2'); + $K2groups[] = JHTML::_('select.option', '0', JText::_('K2_SELECT_K2_GROUP')); + + foreach ($K2userGroups as $K2userGroup) + { + $K2groups[] = JHTML::_('select.option', $K2userGroup->id, $K2userGroup->name); + } + + $lists['filter_group_k2'] = JHTML::_('select.genericlist', $K2groups, 'filter_group_k2', '', 'value', 'text', $filter_group_k2); + + $this->assignRef('lists', $lists); + + if (K2_JVERSION != '15') + { + $dateFormat = JText::_('K2_J16_DATE_FORMAT'); + } + else + { + $dateFormat = JText::_('K2_DATE_FORMAT'); + } + $this->assignRef('dateFormat', $dateFormat); + + $template = $mainframe->getTemplate(); + $this->assignRef('template', $template); + + if ($mainframe->isAdmin()) + { + JToolBarHelper::title(JText::_('K2_USERS'), 'k2.png'); + JToolBarHelper::custom('move', 'move.png', 'move_f2.png', 'K2_MOVE', true); + JToolBarHelper::deleteList('K2_WARNING_YOU_ARE_ABOUT_TO_DELETE_THE_SELECTED_USERS_PERMANENTLY_FROM_THE_SYSTEM', 'delete', 'K2_DELETE'); + JToolBarHelper::publishList('enable', 'K2_ENABLE'); + JToolBarHelper::unpublishList('disable', 'K2_DISABLE'); + JToolBarHelper::editList(); + JToolBarHelper::deleteList('K2_ARE_YOU_SURE_YOU_WANT_TO_RESET_SELECTED_USERS', 'remove', 'K2_RESET_USER_DETAILS'); + + $toolbar = JToolBar::getInstance('toolbar'); + + if (K2_JVERSION != '15') + { + JToolBarHelper::preferences('com_k2', 550, 875, 'K2_PARAMETERS'); + } + else + { + $toolbar->appendButton('Popup', 'config', 'K2_PARAMETERS', 'index.php?option=com_k2&view=settings'); + } + + $this->loadHelper('html'); + K2HelperHTML::subMenu(); + + $user = JFactory::getUser(); + $canImport = false; + if (K2_JVERSION == '15') + { + $canImport = $user->gid > 23; + } + else + { + $canImport = $user->authorise('core.admin', 'com_k2'); + } + if ($canImport) + { + if (!$params->get('hideImportButton')) + { + $buttonUrl = JURI::base().'index.php?option=com_k2&view=users&task=import'; + $buttonText = JText::_('K2_IMPORT_JOOMLA_USERS'); + if (K2_JVERSION == '30') + { + $button = ''.$buttonText.''; + } + else + { + $button = ''.$buttonText.''; + + } + $toolbar->appendButton('Custom', $button); + } + } + + $document = JFactory::getDocument(); + $document->addScriptDeclaration('var K2Language = ["'.JText::_('K2_REPORT_USER_WARNING', true).'"];'); + + } + $isAdmin = $mainframe->isAdmin(); + $this->assignRef('isAdmin', $isAdmin); + + if ($mainframe->isSite()) + { + // CSS + $document->addStyleSheet(JURI::root(true).'/media/k2/assets/css/k2.frontend.css?v=2.6.7'); + $document->addStyleSheet(JURI::root(true).'/templates/system/css/general.css'); + $document->addStyleSheet(JURI::root(true).'/templates/system/css/system.css'); + if (K2_JVERSION != '15') + { + $document->addStyleSheet(JURI::root(true).'/administrator/templates/bluestork/css/template.css'); + $document->addStyleSheet(JURI::root(true).'/media/system/css/system.css'); + } + else + { + $document->addStyleSheet(JURI::root(true).'/administrator/templates/khepri/css/general.css'); + } + } + + parent::display($tpl); + } + + function move() + { + + $mainframe = JFactory::getApplication(); + JTable::addIncludePath(JPATH_COMPONENT.DS.'tables'); + $cid = JRequest::getVar('cid'); + JArrayHelper::toInteger($cid); + + foreach ($cid as $id) + { + $row = JFactory::getUser($id); + $rows[] = $row; + } + $this->assignRef('rows', $rows); + + $model = $this->getModel('users'); + $lists = array(); + $userGroups = $model->getUserGroups(); + $groups[] = JHTML::_('select.option', '', JText::_('K2_DO_NOT_CHANGE')); + foreach ($userGroups as $userGroup) + { + $groups[] = JHTML::_('select.option', $userGroup->value, JText::_($userGroup->text)); + } + $fieldName = 'group'; + $attributes = 'size="10"'; + if (K2_JVERSION != '15') + { + $attributes .= 'multiple="multiple"'; + $fieldName .= '[]'; + } + + $lists['group'] = JHTML::_('select.genericlist', $groups, $fieldName, $attributes, 'value', 'text', ''); + + $K2userGroups = $model->getUserGroups('k2'); + $K2groups[] = JHTML::_('select.option', '0', JText::_('K2_DO_NOT_CHANGE')); + foreach ($K2userGroups as $K2userGroup) + { + $K2groups[] = JHTML::_('select.option', $K2userGroup->id, $K2userGroup->name); + } + $lists['k2group'] = JHTML::_('select.genericlist', $K2groups, 'k2group', 'size="10"', 'value', 'text', 0); + + $this->assignRef('lists', $lists); + + JToolBarHelper::title(JText::_('K2_MOVE_USERS'), 'k2.png'); + JToolBarHelper::custom('saveMove', 'save.png', 'save_f2.png', 'K2_SAVE', false); + JToolBarHelper::cancel(); + + parent::display(); + } + +} diff --git a/administrator/components/com_k2/views/view.php b/administrator/components/com_k2/views/view.php new file mode 100644 index 0000000..6b9fcc4 --- /dev/null +++ b/administrator/components/com_k2/views/view.php @@ -0,0 +1,27 @@ + + +
    + + + + + + +
    +
    diff --git a/administrator/components/com_languages/config.xml b/administrator/components/com_languages/config.xml new file mode 100644 index 0000000..5453162 --- /dev/null +++ b/administrator/components/com_languages/config.xml @@ -0,0 +1,27 @@ + + +
    + + + + + +
    +
    diff --git a/administrator/components/com_languages/controller.php b/administrator/components/com_languages/controller.php new file mode 100644 index 0000000..600b43b --- /dev/null +++ b/administrator/components/com_languages/controller.php @@ -0,0 +1,59 @@ +input->get('view', 'languages'); + $layout = $this->input->get('layout', 'default'); + $id = $this->input->getInt('id'); + + // Check for edit form. + if ($view == 'language' && $layout == 'edit' && !$this->checkEditId('com_languages.edit.language', $id)) { + + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_languages&view=languages', false)); + + return false; + } + + parent::display(); + + return $this; + } +} diff --git a/administrator/components/com_languages/controllers/index.html b/administrator/components/com_languages/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/controllers/installed.php b/administrator/components/com_languages/controllers/installed.php new file mode 100644 index 0000000..db6c68b --- /dev/null +++ b/administrator/components/com_languages/controllers/installed.php @@ -0,0 +1,45 @@ +input->get('cid', ''); + $model = $this->getModel('installed'); + if ($model->publish($cid)) + { + $msg = JText::_('COM_LANGUAGES_MSG_DEFAULT_LANGUAGE_SAVED'); + $type = 'message'; + } + else + { + $msg = $this->getError(); + $type = 'error'; + } + + $clientId = $model->getState('filter.client_id'); + $this->setredirect('index.php?option=com_languages&view=installed&client='.$clientId, $msg, $type); + } +} diff --git a/administrator/components/com_languages/controllers/language.php b/administrator/components/com_languages/controllers/language.php new file mode 100644 index 0000000..2a0adf1 --- /dev/null +++ b/administrator/components/com_languages/controllers/language.php @@ -0,0 +1,35 @@ + true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } +} diff --git a/administrator/components/com_languages/controllers/override.php b/administrator/components/com_languages/controllers/override.php new file mode 100644 index 0000000..9f1d777 --- /dev/null +++ b/administrator/components/com_languages/controllers/override.php @@ -0,0 +1,196 @@ +input->post->get('cid', array(), 'array'); + $context = "$this->option.edit.$this->context"; + + // Get the constant name + $recordId = (count($cid) ? $cid[0] : $this->input->get('id')); + + // Access check + if (!$this->allowEdit()) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_EDIT_NOT_PERMITTED')); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list.$this->getRedirectToListAppend(), false)); + + return; + } + + $app->setUserState($context.'.data', null); + $this->setRedirect('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend($recordId, 'id')); + } + + /** + * Method to save an override + * + * @param string $key The name of the primary key of the URL variable (not used here). + * @param string $urlVar The name of the URL variable if different from the primary key (not used here). + * + * @return void + * + * @since 2.5 + */ + public function save($key = null, $urlVar = null) + { + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $app = JFactory::getApplication(); + $model = $this->getModel(); + $data = $this->input->post->get('jform', array(), 'array'); + $context = "$this->option.edit.$this->context"; + $task = $this->getTask(); + + $recordId = $this->input->get('id'); + $data['id'] = $recordId; + + // Access check + if (!$this->allowSave($data, 'id')) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED')); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list.$this->getRedirectToListAppend(), false)); + + return; + } + + // Validate the posted data + $form = $model->getForm($data, false); + if (!$form) + { + $app->enqueueMessage($model->getError(), 'error'); + + return; + } + + // Require helper for filter functions called by JForm + require_once JPATH_COMPONENT.'/helpers/languages.php'; + + // Test whether the data is valid. + $validData = $model->validate($form, $data); + + // Check for validation errors. + if ($validData === false) + { + // Get the validation messages + $errors = $model->getErrors(); + + // Push up to three validation messages out to the user. + for ($i = 0, $n = count($errors); $i < $n && $i < 3; $i++) + { + if ($errors[$i] instanceof Exception) + { + $app->enqueueMessage($errors[$i]->getMessage(), 'warning'); + } + else + { + $app->enqueueMessage($errors[$i], 'warning'); + } + } + + // Save the data in the session + $app->setUserState($context.'.data', $data); + + // Redirect back to the edit screen + $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend($recordId, 'id'), false)); + + return; + } + + // Attempt to save the data + if (!$model->save($validData)) + { + // Save the data in the session + $app->setUserState($context.'.data', $validData); + + // Redirect back to the edit screen + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError())); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend($recordId, 'id'), false)); + + return; + } + + // Add message of success + $this->setMessage(JText::_('COM_LANGUAGES_VIEW_OVERRIDE_SAVE_SUCCESS')); + + // Redirect the user and adjust session state based on the chosen task + switch ($task) + { + case 'apply': + // Set the record data in the session + $app->setUserState($context.'.data', null); + + // Redirect back to the edit screen + $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend($validData['key'], 'id'), false)); + break; + + case 'save2new': + // Clear the record id and data from the session + $app->setUserState($context.'.data', null); + + // Redirect back to the edit screen + $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend(null, 'id'), false)); + break; + + default: + // Clear the record id and data from the session + $app->setUserState($context.'.data', null); + + // Redirect to the list screen + $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list.$this->getRedirectToListAppend(), false)); + break; + } + } + + /** + * Method to cancel an edit + * + * @param string $key The name of the primary key of the URL variable (not used here). + * + * @return void + * + * @since 2.5 + */ + public function cancel($key = null, $test = null) + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $app = JFactory::getApplication(); + $context = "$this->option.edit.$this->context"; + + $app->setUserState($context.'.data', null); + $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list.$this->getRedirectToListAppend(), false)); + } +} diff --git a/administrator/components/com_languages/controllers/overrides.php b/administrator/components/com_languages/controllers/overrides.php new file mode 100644 index 0000000..358c472 --- /dev/null +++ b/administrator/components/com_languages/controllers/overrides.php @@ -0,0 +1,66 @@ +input->get('cid', array(), 'array'); + + if (!is_array($cid) || count($cid) < 1) + { + $this->setMessage(JText::_($this->text_prefix.'_NO_ITEM_SELECTED'), 'warning'); + } + else + { + // Get the model + $model = $this->getModel('overrides'); + + // Remove the items + if ($model->delete($cid)) + { + $this->setMessage(JText::plural($this->text_prefix.'_N_ITEMS_DELETED', count($cid))); + } + else + { + $this->setMessage($model->getError()); + } + } + + $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list, false)); + } +} diff --git a/administrator/components/com_languages/controllers/strings.json.php b/administrator/components/com_languages/controllers/strings.json.php new file mode 100644 index 0000000..ddc5270 --- /dev/null +++ b/administrator/components/com_languages/controllers/strings.json.php @@ -0,0 +1,44 @@ +getModel('strings')->refresh()); + } + + /** + * Method for searching language strings + * + * @return void + * + * @since 2.5 + */ + public function search() + { + echo new JResponseJson($this->getModel('strings')->search()); + } +} diff --git a/administrator/components/com_languages/helpers/html/index.html b/administrator/components/com_languages/helpers/html/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/helpers/html/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/helpers/html/languages.php b/administrator/components/com_languages/helpers/html/languages.php new file mode 100644 index 0000000..61aa20a --- /dev/null +++ b/administrator/components/com_languages/helpers/html/languages.php @@ -0,0 +1,79 @@ +'; + } + + public static function clients() + { + return array( + JHtml::_('select.option', 0, JText::_('JSITE')), + JHtml::_('select.option', 1, JText::_('JADMINISTRATOR')) + ); + } + + /** + * Returns an array of published state filter options. + * + * @return string The HTML code for the select tag + * @since 1.6 + */ + public static function publishedOptions() + { + // Build the active state filter options. + $options = array(); + $options[] = JHtml::_('select.option', '1', 'JPUBLISHED'); + $options[] = JHtml::_('select.option', '0', 'JUNPUBLISHED'); + $options[] = JHtml::_('select.option', '-2', 'JTRASHED'); + $options[] = JHtml::_('select.option', '*', 'JALL'); + + return $options; + } + +} diff --git a/administrator/components/com_languages/helpers/index.html b/administrator/components/com_languages/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/helpers/jsonresponse.php b/administrator/components/com_languages/helpers/jsonresponse.php new file mode 100644 index 0000000..631f4cf --- /dev/null +++ b/administrator/components/com_languages/helpers/jsonresponse.php @@ -0,0 +1,129 @@ +success, + * so you can use both flags equivalently. + * + * @var boolean + * @since 2.5 + */ + public $error = false; + + /** + * The main response message + * + * @var string + * @since 2.5 + */ + public $message = null; + + /** + * Array of messages gathered in the JApplication object + * + * @var array + * @since 2.5 + */ + public $messages = null; + + /** + * The response data + * + * @var mixed + * @since 2.5 + */ + public $data = null; + + /** + * Constructor + * + * @param mixed $response The Response data + * @param string $message The main response message + * @param boolean $error True, if the success flag shall be set to false, defaults to false + * + * @since 2.5 + * @deprecated 4.0 Use JResponseJson instead + */ + public function __construct($response = null, $message = null, $error = false) + { + JLog::add('Class JJsonResponse is deprecated. Use class JResponseJson instead.', JLog::WARNING, 'deprecated'); + + $this->message = $message; + + // Get the message queue + $messages = JFactory::getApplication()->getMessageQueue(); + + // Build the sorted messages list + if (is_array($messages) && count($messages)) + { + foreach ($messages as $message) + { + if (isset($message['type']) && isset($message['message'])) + { + $lists[$message['type']][] = $message['message']; + } + } + } + + // If messages exist add them to the output + if (isset($lists) && is_array($lists)) + { + $this->messages = $lists; + } + + // Check if we are dealing with an error + if ($response instanceof Exception) + { + // Prepare the error response + $this->success = false; + $this->error = true; + $this->message = $response->getMessage(); + } + else + { + // Prepare the response data + $this->success = !$error; + $this->error = $error; + $this->data = $response; + } + } + + /** + * Magic toString method for sending the response in JSON format + * + * @return string The response in JSON format + * + * @since 2.5 + */ + public function __toString() + { + return json_encode($this); + } +} diff --git a/administrator/components/com_languages/helpers/languages.php b/administrator/components/com_languages/helpers/languages.php new file mode 100644 index 0000000..ebe7367 --- /dev/null +++ b/administrator/components/com_languages/helpers/languages.php @@ -0,0 +1,135 @@ +set($action->name, $user->authorise($action->name, $assetName)); + } + + return $result; + } + + /** + * Method for parsing ini files + * + * @param string $filename Path and name of the ini file to parse + * + * @return array Array of strings found in the file, the array indices will be the keys. On failure an empty array will be returned + * + * @since 2.5 + */ + public static function parseFile($filename) + { + if (!is_file($filename)) + { + return array(); + } + + $contents = file_get_contents($filename); + $contents = str_replace('_QQ_', '"\""', $contents); + $strings = @parse_ini_string($contents); + + if ($strings === false) + { + return array(); + } + + return $strings; + } + + /** + * Filter method for language keys. + * This method will be called by JForm while filtering the form data. + * + * @param string $value The language key to filter + * + * @return string The filtered language key + * + * @since 2.5 + */ + public static function filterKey($value) + { + $filter = JFilterInput::getInstance(null, null, 1, 1); + + return strtoupper($filter->clean($value, 'cmd')); + } + + /** + * Filter method for language strings. + * This method will be called by JForm while filtering the form data. + * + * @param string $value The language string to filter + * + * @return string The filtered language string + * + * @since 2.5 + */ + public static function filterText($value) + { + $filter = JFilterInput::getInstance(null, null, 1, 1); + + return $filter->clean($value); + } +} diff --git a/administrator/components/com_languages/helpers/multilangstatus.php b/administrator/components/com_languages/helpers/multilangstatus.php new file mode 100644 index 0000000..7bf461a --- /dev/null +++ b/administrator/components/com_languages/helpers/multilangstatus.php @@ -0,0 +1,133 @@ +getQuery(true) + ->select('COUNT(*)') + ->from($db->quoteName('#__menu')) + ->where('home = 1') + ->where('published = 1') + ->where('client_id = 0'); + $db->setQuery($query); + return $db->loadResult(); + } + + public static function getLangswitchers() + { + // Check if switcher is published + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('COUNT(*)') + ->from($db->quoteName('#__modules')) + ->where('module = ' . $db->quote('mod_languages')) + ->where('published = 1') + ->where('client_id = 0'); + $db->setQuery($query); + return $db->loadResult(); + } + + public static function getContentlangs() + { + // Check for published Content Languages + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('a.lang_code AS lang_code') + ->select('a.published AS published') + ->from('#__languages AS a'); + $db->setQuery($query); + return $db->loadObjectList(); + } + + public static function getSitelangs() + { + // check for published Site Languages + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('a.element AS element') + ->from('#__extensions AS a') + ->where('a.type = ' . $db->quote('language')) + ->where('a.client_id = 0') + ->where('a.enabled = 1'); + $db->setQuery($query); + return $db->loadObjectList('element'); + } + + public static function getHomepages() + { + // Check for Home pages languages + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('language') + ->from($db->quoteName('#__menu')) + ->where('home = 1') + ->where('published = 1') + ->where('client_id = 0'); + $db->setQuery($query); + return $db->loadObjectList('language'); + } + + public static function getStatus() + { + //check for combined status + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + // Select all fields from the languages table. + $query->select('a.*', 'l.home') + ->select('a.published AS published') + ->select('a.lang_code AS lang_code') + ->from('#__languages AS a'); + + // Select the language home pages + $query->select('l.home AS home') + ->select('l.language AS home_language') + ->join('LEFT', '#__menu AS l ON l.language = a.lang_code AND l.home=1 AND l.published=1 AND l.language <> \'*\'') + ->select('e.enabled AS enabled') + ->select('e.element AS element') + ->join('LEFT', '#__extensions AS e ON e.element = a.lang_code') + ->where('e.client_id = 0') + ->where('e.enabled = 1') + ->where('e.state = 0'); + + $db->setQuery($query); + return $db->loadObjectList(); + } + + public static function getContacts() + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('u.name, count(cd.language) as counted, MAX(cd.language=' . $db->quote('*') . ') as all_languages') + ->from('#__users AS u') + ->join('LEFT', '#__contact_details AS cd ON cd.user_id=u.id') + ->join('LEFT', '#__languages as l on cd.language=l.lang_code') + ->where('EXISTS (SELECT * from #__content as c where c.created_by=u.id)') + ->where('(l.published=1 or cd.language=' . $db->quote('*') . ')') + ->where('cd.published=1') + ->group('u.id') + ->having('(counted !=' . count(JLanguageHelper::getLanguages()) . ' OR all_languages=1)') + ->having('(counted !=1 OR all_languages=0)'); + $db->setQuery($query); + return $db->loadObjectList(); + } +} diff --git a/administrator/components/com_languages/index.html b/administrator/components/com_languages/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/languages.php b/administrator/components/com_languages/languages.php new file mode 100644 index 0000000..8abcd3f --- /dev/null +++ b/administrator/components/com_languages/languages.php @@ -0,0 +1,19 @@ +authorise('core.manage', 'com_languages')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$controller = JControllerLegacy::getInstance('Languages'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_languages/languages.xml b/administrator/components/com_languages/languages.xml new file mode 100644 index 0000000..402c8c6 --- /dev/null +++ b/administrator/components/com_languages/languages.xml @@ -0,0 +1,32 @@ + + + com_languages + Joomla! Project + 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + + GNU General Public License version 2 or later; see + LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_LANGUAGES_XML_DESCRIPTION + + + config.xml + controller.php + index.html + languages.php + controllers + helpers + models + tables + views + + + language/en-GB.com_languages.ini + language/en-GB.com_languages.sys.ini + + + + diff --git a/administrator/components/com_languages/models/forms/index.html b/administrator/components/com_languages/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/models/forms/language.xml b/administrator/components/com_languages/models/forms/language.xml new file mode 100644 index 0000000..7e8247d --- /dev/null +++ b/administrator/components/com_languages/models/forms/language.xml @@ -0,0 +1,113 @@ + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    +
    + +
    +
    diff --git a/administrator/components/com_languages/models/forms/override.xml b/administrator/components/com_languages/models/forms/override.xml new file mode 100644 index 0000000..7f1851c --- /dev/null +++ b/administrator/components/com_languages/models/forms/override.xml @@ -0,0 +1,83 @@ + +
    +
    + + + + + + + + + + + + + + + + + + + + +
    +
    diff --git a/administrator/components/com_languages/models/index.html b/administrator/components/com_languages/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/models/installed.php b/administrator/components/com_languages/models/installed.php new file mode 100644 index 0000000..311df35 --- /dev/null +++ b/administrator/components/com_languages/models/installed.php @@ -0,0 +1,384 @@ +input->getInt('client'); + $this->setState('filter.client_id', $clientId); + + // Load the parameters. + $params = JComponentHelper::getParams('com_languages'); + $this->setState('params', $params); + + // List state information. + parent::populateState('a.name', 'asc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + * @since 1.6 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':'.$this->getState('filter.client_id'); + + return parent::getStoreId($id); + } + + /** + * Method to get the client object + * + * @return object + * @since 1.6 + */ + public function &getClient() + { + if (is_null($this->client)) + { + $this->client = JApplicationHelper::getClientInfo($this->getState('filter.client_id', 0)); + } + + return $this->client; + } + + /** + * Method to get the ftp credentials + * + * @return object + * @since 1.6 + */ + public function &getFtp() + { + if (is_null($this->ftp)) + { + $this->ftp = JClientHelper::setCredentialsFromRequest('ftp'); + } + + return $this->ftp; + } + + /** + * Method to get the option + * + * @return object + * @since 1.6 + */ + public function &getOption() + { + $option = $this->getState('option'); + + return $option; + } + + /** + * Method to get Languages item data + * + * @return array + * @since 1.6 + */ + public function &getData() + { + if (is_null($this->data)) { + + // Get information + $path = $this->getPath(); + $client = $this->getClient(); + $langlist = $this->getLanguageList(); + + // Compute all the languages + $data = array (); + + foreach ($langlist as $lang) { + $file = $path . '/' . $lang . '/' . $lang.'.xml'; + $info = JApplicationHelper::parseXMLLangMetaFile($file); + $row = new JObject; + $row->language = $lang; + + if (!is_array($info)) + { + continue; + } + + foreach ($info as $key => $value) + { + $row->$key = $value; + } + + // if current than set published + $params = JComponentHelper::getParams('com_languages'); + if ($params->get($client->name, 'en-GB') == $row->language) + { + $row->published = 1; + } + else { + $row->published = 0; + } + + $row->checked_out = 0; + $data[] = $row; + } + usort($data, array($this, 'compareLanguages')); + + // Prepare data + $limit = $this->getState('list.limit'); + $start = $this->getState('list.start'); + $total = $this->getTotal(); + + if ($limit == 0) + { + $start = 0; + $end = $total; + } + else { + if ($start > $total) + { + $start = $total - $total % $limit; + } + $end = $start + $limit; + + if ($end > $total) + { + $end = $total; + } + } + + // Compute the displayed languages + $this->data = array(); + for ($i = $start;$i < $end;$i++) + { + $this->data[] = & $data[$i]; + } + } + + return $this->data; + } + + /** + * Method to get installed languages data. + * + * @return string An SQL query + * @since 1.6 + */ + protected function getLanguageList() + { + // Create a new db object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + $client = $this->getState('filter.client_id'); + $type = "language"; + // Select field element from the extensions table. + $query->select($this->getState('list.select', 'a.element')) + ->from('#__extensions AS a'); + + $type = $db->quote($type); + $query->where('(a.type = '.$type.')') + + ->where('state = 0') + ->where('enabled = 1') + + ->where('client_id=' . (int) $client); + + // for client_id = 1 do we need to check language table also ? + $db->setQuery($query); + + $this->langlist = $db->loadColumn(); + + return $this->langlist; + } + + /** + * Method to get the total number of Languages items + * + * @return integer + * @since 1.6 + */ + public function getTotal() + { + if (is_null($this->total)) + { + $langlist = $this->getLanguageList(); + $this->total = count($langlist); + } + + return $this->total; + } + + /** + * Method to set the default language + * + * @return boolean + * @since 1.6 + */ + public function publish($cid) + { + if ($cid) + { + $client = $this->getClient(); + + $params = JComponentHelper::getParams('com_languages'); + $params->set($client->name, $cid); + + $table = JTable::getInstance('extension'); + $id = $table->find(array('element' => 'com_languages')); + + // Load + if (!$table->load($id)) + { + $this->setError($table->getError()); + return false; + } + + $table->params = (string) $params; + // pre-save checks + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // save the changes + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + } + else + { + $this->setError(JText::_('COM_LANGUAGES_ERR_NO_LANGUAGE_SELECTED')); + return false; + } + + // Clean the cache of com_languages and component cache. + $this->cleanCache(); + $this->cleanCache('_system'); + + return true; + } + + /** + * Method to get the folders + * + * @return array Languages folders + * @since 1.6 + */ + protected function getFolders() + { + if (is_null($this->folders)) + { + $path = $this->getPath(); + jimport('joomla.filesystem.folder'); + $this->folders = JFolder::folders($path, '.', false, false, array('.svn', 'CVS', '.DS_Store', '__MACOSX', 'pdf_fonts', 'overrides')); + } + + return $this->folders; + } + + /** + * Method to get the path + * + * @return string The path to the languages folders + * @since 1.6 + */ + protected function getPath() + { + if (is_null($this->path)) + { + $client = $this->getClient(); + $this->path = JLanguage::getLanguagePath($client->path); + } + + return $this->path; + } + + /** + * Method to compare two languages in order to sort them + * + * @param object $lang1 the first language + * @param object $lang2 the second language + * + * @return integer + * @since 1.6 + */ + protected function compareLanguages($lang1, $lang2) + { + return strcmp($lang1->name, $lang2->name); + } +} diff --git a/administrator/components/com_languages/models/language.php b/administrator/components/com_languages/models/language.php new file mode 100644 index 0000000..87903b0 --- /dev/null +++ b/administrator/components/com_languages/models/language.php @@ -0,0 +1,204 @@ +input->getInt('lang_id'); + $this->setState('language.id', $langId); + + // Load the parameters. + $this->setState('params', $params); + } + + /** + * Method to get a member item. + * + * @param integer The id of the member to get. + * + * @return mixed User data object on success, false on failure. + * @since 1.0 + */ + public function getItem($langId = null) + { + $langId = (!empty($langId)) ? $langId : (int) $this->getState('language.id'); + $false = false; + + // Get a member row instance. + $table = $this->getTable(); + + // Attempt to load the row. + $return = $table->load($langId); + + // Check for a table object error. + if ($return === false && $table->getError()) + { + $this->setError($table->getError()); + return $false; + } + + $properties = $table->getProperties(1); + $value = JArrayHelper::toObject($properties, 'JObject'); + + return $value; + } + + /** + * Method to get the group form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * + * @return mixed A JForm object on success, false on failure + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + // Get the form. + $form = $this->loadForm('com_languages.language', 'language', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_languages.edit.language.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + } + + $this->preprocessData('com_languages.language', $data); + + return $data; + } + + /** + * Method to save the form data. + * + * @param array The form data. + * + * @return boolean True on success. + * @since 1.6 + */ + public function save($data) + { + $langId = (int) $this->getState('language.id'); + $isNew = true; + + $dispatcher = JEventDispatcher::getInstance(); + JPluginHelper::importPlugin('extension'); + + $table = $this->getTable(); + + // Load the row if saving an existing item. + if ($langId > 0) + { + $table->load($langId); + $isNew = false; + } + + // Bind the data + if (!$table->bind($data)) + { + $this->setError($table->getError()); + return false; + } + + // Check the data + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // Trigger the onExtensionBeforeSave event. + $result = $dispatcher->trigger('onExtensionBeforeSave', array('com_languages.language', &$table, $isNew)); + + // Check the event responses. + if (in_array(false, $result, true)) + { + $this->setError($table->getError()); + return false; + } + + // Store the data + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Trigger the onExtensionAfterSave event. + $dispatcher->trigger('onExtensionAfterSave', array('com_languages.language', &$table, $isNew)); + + $this->setState('language.id', $table->lang_id); + + // Clean the cache. + $this->cleanCache(); + + return true; + } + + /** + * Custom clean cache method + * + * @since 1.6 + */ + protected function cleanCache($group = null, $client_id = 0) + { + parent::cleanCache('_system'); + parent::cleanCache('com_languages'); + } +} diff --git a/administrator/components/com_languages/models/languages.php b/administrator/components/com_languages/models/languages.php new file mode 100644 index 0000000..7d69828 --- /dev/null +++ b/administrator/components/com_languages/models/languages.php @@ -0,0 +1,215 @@ +getUserStateFromRequest($this->context . '.search', 'filter_search'); + $this->setState('filter.search', $search); + + $accessId = $this->getUserStateFromRequest($this->context . '.access', 'filter_access', null, 'int'); + $this->setState('filter.access', $accessId); + + $published = $this->getUserStateFromRequest($this->context . '.published', 'filter_published', ''); + $this->setState('filter.published', $published); + + // Load the parameters. + $params = JComponentHelper::getParams('com_languages'); + $this->setState('params', $params); + + // List state information. + parent::populateState('a.title', 'asc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + * @since 1.6 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.access'); + $id .= ':' . $this->getState('filter.published'); + + return parent::getStoreId($id); + } + + /** + * Method to build an SQL query to load the list data. + * + * @return string An SQL query + * @since 1.6 + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Select all fields from the languages table. + $query->select($this->getState('list.select', 'a.*', 'l.home')) + ->from($db->quoteName('#__languages') . ' AS a'); + + // Join over the asset groups. + $query->select('ag.title AS access_level') + ->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access'); + + // Select the language home pages + $query->select('l.home AS home') + ->join('LEFT', $db->quoteName('#__menu') . ' AS l ON l.language = a.lang_code AND l.home=1 AND l.language <> ' . $db->quote('*')); + + // Filter on the published state. + $published = $this->getState('filter.published'); + if (is_numeric($published)) + { + $query->where('a.published = ' . (int) $published); + } + elseif ($published === '') + { + $query->where('(a.published IN (0, 1))'); + } + + // Filter by search in title + $search = $this->getState('filter.search'); + if (!empty($search)) + { + $search = $db->quote('%' . $db->escape($search, true) . '%', false); + $query->where('(a.title LIKE ' . $search . ')'); + } + + // Filter by access level. + if ($access = $this->getState('filter.access')) + { + $query->where('a.access = ' . (int) $access); + } + + // Add the list ordering clause. + $query->order($db->escape($this->getState('list.ordering', 'a.ordering')) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))); + + return $query; + } + + /** + * Set the published language(s) + * + * @param array $cid An array of language IDs. + * @param integer $value The value of the published state. + * + * @return boolean True on success, false otherwise. + * @since 1.6 + */ + public function setPublished($cid, $value = 0) + { + return JTable::getInstance('Language')->publish($cid, $value); + } + + /** + * Method to delete records. + * + * @param array An array of item primary keys. + * + * @return boolean Returns true on success, false on failure. + * @since 1.6 + */ + public function delete($pks) + { + // Sanitize the array. + $pks = (array) $pks; + + // Get a row instance. + $table = JTable::getInstance('Language'); + + // Iterate the items to delete each one. + foreach ($pks as $itemId) + { + if (!$table->delete((int) $itemId)) + { + $this->setError($table->getError()); + + return false; + } + } + + // Clean the cache. + $this->cleanCache(); + + return true; + } + + /** + * Custom clean cache method, 2 places for 2 clients + * + * @since 1.6 + */ + protected function cleanCache($group = null, $client_id = 0) + { + parent::cleanCache('_system'); + parent::cleanCache('com_languages'); + } +} diff --git a/administrator/components/com_languages/models/override.php b/administrator/components/com_languages/models/override.php new file mode 100644 index 0000000..51b27b9 --- /dev/null +++ b/administrator/components/com_languages/models/override.php @@ -0,0 +1,204 @@ +loadForm('com_languages.override', 'override', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + $client = $this->getState('filter.client', 'site'); + $language = $this->getState('filter.language', 'en-GB'); + $langName = JLanguage::getInstance($language)->getName(); + if (!$langName) + { + // If a language only exists in frontend, it's meta data cannot be + // loaded in backend at the moment, so fall back to the language tag + $langName = $language; + } + $form->setValue('client', null, JText::_('COM_LANGUAGES_VIEW_OVERRIDE_CLIENT_'.strtoupper($client))); + $form->setValue('language', null, JText::sprintf('COM_LANGUAGES_VIEW_OVERRIDE_LANGUAGE', $langName, $language)); + $form->setValue('file', null, JPath::clean(constant('JPATH_'.strtoupper($client)) . '/language/overrides/' . $language . '.override.ini')); + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form + * + * @since 2.5 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_languages.edit.override.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + } + + $this->preprocessData('com_languages.override', $data); + + return $data; + } + + /** + * Method to get a single record. + * + * @param string $pk The key name. + * + * @return mixed Object on success, false otherwise. + * + * @since 2.5 + */ + public function getItem($pk = null) + { + require_once JPATH_COMPONENT.'/helpers/languages.php'; + + $input = JFactory::getApplication()->input; + $pk = (!empty($pk)) ? $pk : $input->get('id'); + $filename = constant('JPATH_'.strtoupper($this->getState('filter.client'))) . '/language/overrides/' . $this->getState('filter.language', 'en-GB').'.override.ini'; + $strings = LanguagesHelper::parseFile($filename); + + $result = new stdClass; + $result->key = ''; + $result->override = ''; + if (isset($strings[$pk])) + { + $result->key = $pk; + $result->override = $strings[$pk]; + } + + return $result; + } + + /** + * Method to save the form data. + * + * @param array $data The form data. + * @param boolean $opposite_client Indicates whether the override should not be created for the current client + * + * @return boolean True on success, false otherwise. + * + * @since 2.5 + */ + public function save($data, $opposite_client = false) + { + $app = JFactory::getApplication(); + require_once JPATH_COMPONENT.'/helpers/languages.php'; + jimport('joomla.filesystem.file'); + + $client = $app->getUserState('com_languages.overrides.filter.client', 0); + $language = $app->getUserState('com_languages.overrides.filter.language', 'en-GB'); + + // If the override should be created for both + if ($opposite_client) + { + $client = 1 - $client; + } + + $client = $client ? 'administrator' : 'site'; + + // Parse the override.ini file in oder to get the keys and strings + $filename = constant('JPATH_'.strtoupper($client)) . '/language/overrides/' . $language . '.override.ini'; + $strings = LanguagesHelper::parseFile($filename); + + if (isset($strings[$data['id']])) + { + // If an existent string was edited check whether + // the name of the constant is still the same + if ($data['key'] == $data['id']) + { + // If yes, simply override it + $strings[$data['key']] = $data['override']; + } + else + { + // If no, delete the old string and prepend the new one + unset($strings[$data['id']]); + $strings = array($data['key'] => $data['override']) + $strings; + } + } + else + { + // If it is a new override simply prepend it + $strings = array($data['key'] => $data['override']) + $strings; + } + + foreach ($strings as $key => $string) + { + $strings[$key] = str_replace('"', '"_QQ_"', $string); + } + + // Write override.ini file with the strings + $registry = new JRegistry; + $registry->loadObject($strings); + + if (!JFile::write($filename, $registry->toString('INI'))) + { + return false; + } + + // If the override should be stored for both clients save + // it also for the other one and prevent endless recursion + if (isset($data['both']) && $data['both'] && !$opposite_client) + { + return $this->save($data, true); + } + + return true; + } + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @return void + * + * @since 2.5 + */ + protected function populateState() + { + $app = JFactory::getApplication(); + + $client = $app->getUserStateFromRequest('com_languages.overrides.filter.client', 'filter_client', 0, 'int') ? 'administrator' : 'site'; + $this->setState('filter.client', $client); + + $language = $app->getUserStateFromRequest('com_languages.overrides.filter.language', 'filter_language', 'en-GB', 'cmd'); + $this->setState('filter.language', $language); + } +} diff --git a/administrator/components/com_languages/models/overrides.php b/administrator/components/com_languages/models/overrides.php new file mode 100644 index 0000000..f692fdb --- /dev/null +++ b/administrator/components/com_languages/models/overrides.php @@ -0,0 +1,264 @@ +filter_fields = array('key', 'text'); + } + + /** + * Retrieves the overrides data + * + * @param boolean True if all overrides shall be returned without considering pagination, defaults to false + * + * @return array Array of objects containing the overrides of the override.ini file + * + * @since 2.5 + */ + public function getOverrides($all = false) + { + // Get a storage key + $store = $this->getStoreId(); + + // Try to load the data from internal storage + if (!empty($this->cache[$store])) + { + return $this->cache[$store]; + } + + // Parse the override.ini file in oder to get the keys and strings + $filename = constant('JPATH_' . strtoupper($this->getState('filter.client'))) . '/language/overrides/' . $this->getState('filter.language') . '.override.ini'; + $strings = LanguagesHelper::parseFile($filename); + + // Consider the odering + if ($this->getState('list.ordering') == 'text') + { + if (strtoupper($this->getState('list.direction')) == 'DESC') + { + arsort($strings); + } + else + { + asort($strings); + } + } + else + { + if (strtoupper($this->getState('list.direction')) == 'DESC') + { + krsort($strings); + } + else + { + ksort($strings); + } + } + + // Consider the pagination + if (!$all && $this->getState('list.limit') && $this->getTotal() > $this->getState('list.limit')) + { + $strings = array_slice($strings, $this->getStart(), $this->getState('list.limit'), true); + } + + // Add the items to the internal cache + $this->cache[$store] = $strings; + + return $this->cache[$store]; + } + + /** + * Method to get the total number of overrides + * + * @return int The total number of overrides + * + * @since 2.5 + */ + public function getTotal() + { + // Get a storage key + $store = $this->getStoreId('getTotal'); + + // Try to load the data from internal storage + if (!empty($this->cache[$store])) + { + return $this->cache[$store]; + } + + // Add the total to the internal cache + $this->cache[$store] = count($this->getOverrides(true)); + + return $this->cache[$store]; + } + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @param string An optional ordering field. + * @param string An optional direction (asc|desc). + * + * @return void + * + * @since 2.5 + */ + protected function populateState($ordering = null, $direction = null) + { + $app = JFactory::getApplication(); + + // Use default language of frontend for default filter + $default = JComponentHelper::getParams('com_languages')->get('site').'0'; + + $old_language_client = $app->getUserState('com_languages.overrides.filter.language_client', ''); + $language_client = $this->getUserStateFromRequest('com_languages.overrides.filter.language_client', 'filter_language_client', $default, 'cmd'); + + if ($old_language_client != $language_client) + { + $client = substr($language_client, -1); + $language = substr($language_client, 0, -1); + } + else + { + $client = $app->getUserState('com_languages.overrides.filter.client', 0); + $language = $app->getUserState('com_languages.overrides.filter.language', 'en-GB'); + } + + $this->setState('filter.language_client', $language.$client); + $this->setState('filter.client', $client ? 'administrator' : 'site'); + $this->setState('filter.language', $language); + + // Add filters to the session because they won't be stored there + // by 'getUserStateFromRequest' if they aren't in the current request + $app->setUserState('com_languages.overrides.filter.client', $client); + $app->setUserState('com_languages.overrides.filter.language', $language); + + // List state information + parent::populateState('key', 'asc'); + } + + /** + * Method to get all found languages of frontend and backend. + * + * The resulting array has entries of the following style: + * 0|1 => - + * + * @return array Sorted associative array of languages + * + * @since 2.5 + */ + public function getLanguages() + { + // Try to load the data from internal storage + if (!empty($this->cache['languages'])) + { + return $this->cache['languages']; + } + + // Get all languages of frontend and backend + $languages = array(); + $site_languages = JLanguage::getKnownLanguages(JPATH_SITE); + $admin_languages = JLanguage::getKnownLanguages(JPATH_ADMINISTRATOR); + + // Create a single array of them + foreach ($site_languages as $tag => $language) + { + $languages[$tag.'0'] = JText::sprintf('COM_LANGUAGES_VIEW_OVERRIDES_LANGUAGES_BOX_ITEM', $language['name'], JText::_('JSITE')); + } + foreach ($admin_languages as $tag => $language) + { + $languages[$tag.'1'] = JText::sprintf('COM_LANGUAGES_VIEW_OVERRIDES_LANGUAGES_BOX_ITEM', $language['name'], JText::_('JADMINISTRATOR')); + } + + // Sort it by language tag and by client after that + ksort($languages); + + // Add the languages to the internal cache + $this->cache['languages'] = $languages; + + return $this->cache['languages']; + } + + /** + * Method to delete one or more overrides + * + * @param array Array of keys to delete + * + * @return integer Number of successfully deleted overrides, boolean false if an error occured + * + * @since 2.5 + */ + public function delete($cids) + { + // Check permissions first + if (!JFactory::getUser()->authorise('core.delete', 'com_languages')) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED')); + + return false; + } + + jimport('joomla.filesystem.file'); + require_once JPATH_COMPONENT.'/helpers/languages.php'; + + // Parse the override.ini file in oder to get the keys and strings + $filename = constant('JPATH_' . strtoupper($this->getState('filter.client'))) . '/language/overrides/' . $this->getState('filter.language') . '.override.ini'; + $strings = LanguagesHelper::parseFile($filename); + + // Unset strings that shall be deleted + foreach ($cids as $key) + { + if (isset($strings[$key])) + { + unset($strings[$key]); + } + } + + foreach ($strings as $key => $string) + { + $strings[$key] = str_replace('"', '"_QQ_"', $string); + } + + // Write override.ini file with the left strings + $registry = new JRegistry; + $registry->loadObject($strings); + + $filename = constant('JPATH_' . strtoupper($this->getState('filter.client'))) . '/language/overrides/' . $this->getState('filter.language') . '.override.ini'; + + if (!JFile::write($filename, $registry->toString('INI'))) + { + return false; + } + + $this->cleanCache(); + + return count($cids); + } +} diff --git a/administrator/components/com_languages/models/strings.php b/administrator/components/com_languages/models/strings.php new file mode 100644 index 0000000..dd8fcb9 --- /dev/null +++ b/administrator/components/com_languages/models/strings.php @@ -0,0 +1,163 @@ +setUserState('com_languages.overrides.cachedtime', null); + + // Empty the database cache first + try + { + $this->_db->setQuery('TRUNCATE TABLE '.$this->_db->quoteName('#__overrider')); + $this->_db->execute(); + } + catch (RuntimeException $e) + { + return $e; + } + + // Create the insert query + $query = $this->_db->getQuery(true) + ->insert($this->_db->quoteName('#__overrider')) + ->columns('constant, string, file'); + + // Initialize some variables + $client = $app->getUserState('com_languages.overrides.filter.client', 'site') ? 'administrator' : 'site'; + $language = $app->getUserState('com_languages.overrides.filter.language', 'en-GB'); + + $base = constant('JPATH_'.strtoupper($client)); + $path = $base . '/language/' . $language; + + $files = array(); + + // Parse common language directory + jimport('joomla.filesystem.folder'); + if (is_dir($path)) + { + $files = JFolder::files($path, $language.'.*ini$', false, true); + } + + // Parse language directories of components + $files = array_merge($files, JFolder::files($base.'/components', $language.'.*ini$', 3, true)); + + // Parse language directories of modules + $files = array_merge($files, JFolder::files($base.'/modules', $language.'.*ini$', 3, true)); + + // Parse language directories of templates + $files = array_merge($files, JFolder::files($base.'/templates', $language.'.*ini$', 3, true)); + + // Parse language directories of plugins + $files = array_merge($files, JFolder::files(JPATH_PLUGINS, $language.'.*ini$', 3, true)); + + // Parse all found ini files and add the strings to the database cache + foreach ($files as $file) + { + $strings = LanguagesHelper::parseFile($file); + if ($strings && count($strings)) + { + $query->clear('values'); + foreach ($strings as $key => $string) + { + $query->values($this->_db->quote($key).','.$this->_db->quote($string).','.$this->_db->quote(JPath::clean($file))); + } + + try + { + $this->_db->setQuery($query); + $this->_db->execute(); + } + catch (RuntimeException $e) + { + return $e; + } + } + } + + // Update the cached time + $app->setUserState('com_languages.overrides.cachedtime.'.$client.'.'.$language, time()); + + return true; + } + + /** + * Method for searching language strings + * + * @return array Array of resuls on success, Exception object otherwise + * + * @since 2.5 + */ + public function search() + { + $results = array(); + $input = JFactory::getApplication()->input; + + $limitstart = $input->getInt('more'); + + try + { + $searchstring = $this->_db->quote('%' . $input->getString('searchstring') . '%'); + + // Create the search query + $query = $this->_db->getQuery(true) + ->select('constant, string, file') + ->from($this->_db->quoteName('#__overrider')); + if ($input->get('searchtype') == 'constant') + { + $query->where('constant LIKE '.$searchstring); + } + else + { + $query->where('string LIKE '.$searchstring); + } + + // Consider the limitstart according to the 'more' parameter and load the results + $this->_db->setQuery($query, $limitstart, 10); + $results['results'] = $this->_db->loadObjectList(); + + // Check whether there are more results than already loaded + $query->clear('select') + ->select('COUNT(id)'); + $this->_db->setQuery($query); + + if ($this->_db->loadResult() > $limitstart + 10) + { + // If this is set a 'More Results' link will be displayed in the view + $results['more'] = $limitstart + 10; + } + } + catch (RuntimeException $e) + { + return $e; + } + + return $results; + } +} diff --git a/administrator/components/com_languages/views/index.html b/administrator/components/com_languages/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/views/installed/index.html b/administrator/components/com_languages/views/installed/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/views/installed/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/views/installed/tmpl/default.php b/administrator/components/com_languages/views/installed/tmpl/default.php new file mode 100644 index 0000000..eb0e9a2 --- /dev/null +++ b/administrator/components/com_languages/views/installed/tmpl/default.php @@ -0,0 +1,111 @@ +get('id'); +$client = $this->state->get('filter.client_id', 0) ? JText::_('JADMINISTRATOR') : JText::_('JSITE'); +$clientId = $this->state->get('filter.client_id', 0); +?> +
    + sidebar)) : ?> +
    + sidebar; ?> +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + rows as $i => $row) : + $canCreate = $user->authorise('core.create', 'com_languages'); + $canEdit = $user->authorise('core.edit', 'com_languages'); + $canChange = $user->authorise('core.edit.state', 'com_languages'); + ?> + + + + + + + + + + + + + +
    +   + + + + + + + + + + + + + + + + +
    + pagination->getListFooter(); ?> +
    + language);?> + + escape($row->name); ?> + + escape($row->language); ?> + + + + published, $i, 'installed.', !$row->published && $canChange);?> + + escape($row->version); ?> + + escape($row->creationDate); ?> + + escape($row->author); ?> + + escape($row->authorEmail)); ?> +
    + + + + +
    + diff --git a/administrator/components/com_languages/views/installed/tmpl/index.html b/administrator/components/com_languages/views/installed/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/views/installed/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/views/installed/view.html.php b/administrator/components/com_languages/views/installed/view.html.php new file mode 100644 index 0000000..4f24978 --- /dev/null +++ b/administrator/components/com_languages/views/installed/view.html.php @@ -0,0 +1,103 @@ +ftp = $this->get('Ftp'); + $this->option = $this->get('Option'); + $this->pagination = $this->get('Pagination'); + $this->rows = $this->get('Data'); + $this->state = $this->get('State'); + + $client = (int) $this->state->get('filter.client_id', 0); + LanguagesHelper::addSubmenu('installed', $client); + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + require_once JPATH_COMPONENT.'/helpers/languages.php'; + + $canDo = LanguagesHelper::getActions(); + + JToolbarHelper::title(JText::_('COM_LANGUAGES_VIEW_INSTALLED_TITLE'), 'langmanager.png'); + + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::makeDefault('installed.setDefault'); + JToolbarHelper::divider(); + } + + if ($canDo->get('core.admin')) + { + // Add install languages link to the lang installer component + $bar = JToolbar::getInstance('toolbar'); + $bar->appendButton('Link', 'upload', 'COM_LANGUAGES_INSTALL', 'index.php?option=com_installer&view=languages'); + JToolbarHelper::divider(); + + JToolbarHelper::preferences('com_languages'); + JToolbarHelper::divider(); + } + + JToolbarHelper::help('JHELP_EXTENSIONS_LANGUAGE_MANAGER_INSTALLED'); + + $this->sidebar = JHtmlSidebar::render(); + } +} diff --git a/administrator/components/com_languages/views/language/index.html b/administrator/components/com_languages/views/language/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/views/language/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/views/language/tmpl/edit.php b/administrator/components/com_languages/views/language/tmpl/edit.php new file mode 100644 index 0000000..79d1206 --- /dev/null +++ b/administrator/components/com_languages/views/language/tmpl/edit.php @@ -0,0 +1,177 @@ + + + +
    + + + +
    + 'details')); ?> + + +
    +
    + item->lang_id) : ?> + item->lang_id); ?> + + + +
    +
    + +
    +
    + form->getLabel('title'); ?> +
    +
    + form->getInput('title'); ?> +
    +
    +
    +
    + form->getLabel('title_native'); ?> +
    +
    + form->getInput('title_native'); ?> +
    +
    +
    +
    + form->getLabel('sef'); ?> +
    +
    + form->getInput('sef'); ?> +
    +
    +
    +
    + form->getLabel('image'); ?> +
    +
    + form->getInput('image'); ?> + + form->getValue('image') . '.gif', $this->form->getValue('image'), array('title' => $this->form->getValue('image')), true); ?> + +
    +
    +
    +
    + form->getLabel('lang_code'); ?> +
    +
    + form->getInput('lang_code'); ?> +
    +
    + get('core.edit.state')) : ?> +
    +
    + form->getLabel('published'); ?> +
    +
    + form->getInput('published'); ?> +
    +
    + + +
    +
    + form->getLabel('access'); ?> +
    +
    + form->getInput('access'); ?> +
    +
    +
    +
    + form->getLabel('description'); ?> +
    +
    + form->getInput('description'); ?> +
    +
    +
    +
    + form->getLabel('lang_id'); ?> +
    +
    + form->getInput('lang_id'); ?> +
    +
    + + + + form->getFieldset('metadata') as $field) : ?> +
    + hidden) : ?> +
    + label; ?> +
    + +
    + input; ?> +
    +
    + + + + + form->getFieldset('site_name') as $field) : ?> +
    + hidden) : ?> +
    + label; ?> +
    + +
    + input; ?> +
    +
    + + + + +
    + + +
    + diff --git a/administrator/components/com_languages/views/language/tmpl/index.html b/administrator/components/com_languages/views/language/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/views/language/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/views/language/view.html.php b/administrator/components/com_languages/views/language/view.html.php new file mode 100644 index 0000000..7d692fa --- /dev/null +++ b/administrator/components/com_languages/views/language/view.html.php @@ -0,0 +1,95 @@ +item = $this->get('Item'); + $this->form = $this->get('Form'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + require_once JPATH_COMPONENT . '/helpers/languages.php'; + + JFactory::getApplication()->input->set('hidemainmenu', 1); + $isNew = empty($this->item->lang_id); + $canDo = LanguagesHelper::getActions(); + + JToolbarHelper::title(JText::_($isNew ? 'COM_LANGUAGES_VIEW_LANGUAGE_EDIT_NEW_TITLE' : 'COM_LANGUAGES_VIEW_LANGUAGE_EDIT_EDIT_TITLE'), 'langmanager.png'); + + // If a new item, can save. + if ($isNew && $canDo->get('core.create')) + { + JToolbarHelper::save('language.save'); + } + + //If an existing item, allow to Apply and Save. + if (!$isNew && $canDo->get('core.edit')) + { + JToolbarHelper::apply('language.apply'); + JToolbarHelper::save('language.save'); + } + + // If an existing item, can save to a copy only if we have create rights. + if ($canDo->get('core.create')) + { + JToolbarHelper::save2new('language.save2new'); + } + + if ($isNew) + { + JToolbarHelper::cancel('language.cancel'); + } + else + { + JToolbarHelper::cancel('language.cancel', 'JTOOLBAR_CLOSE'); + } + + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_EXTENSIONS_LANGUAGE_MANAGER_EDIT'); + + $this->sidebar = JHtmlSidebar::render(); + } +} diff --git a/administrator/components/com_languages/views/languages/index.html b/administrator/components/com_languages/views/languages/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/views/languages/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/views/languages/tmpl/default.php b/administrator/components/com_languages/views/languages/tmpl/default.php new file mode 100644 index 0000000..9878565 --- /dev/null +++ b/administrator/components/com_languages/views/languages/tmpl/default.php @@ -0,0 +1,167 @@ +get('id'); +$n = count($this->items); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$canOrder = $user->authorise('core.edit.state', 'com_languages'); +$saveOrder = $listOrder == 'a.ordering'; +?> + +
    +sidebar)) : ?> +
    + sidebar; ?> +
    +
    + +
    + +
    + +
    + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + items as $i => $item) : + $ordering = ($listOrder == 'a.ordering'); + $canCreate = $user->authorise('core.create', 'com_languages'); + $canEdit = $user->authorise('core.edit', 'com_languages'); + $canChange = $user->authorise('core.edit.state', 'com_languages'); + ?> + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + items, 'filesave.png', 'languages.saveorder'); ?> + + + + + + + +
    + pagination->getListFooter(); ?> +
    + lang_id); ?> + + published, $i, 'languages.', $canChange);?> + + + + escape($item->title); ?> + + escape($item->title); ?> + + + + escape($item->title_native); ?> + + escape($item->lang_code); ?> + + escape($item->sef); ?> + + escape($item->image); ?> image.'.gif', $item->image, array('title' => $item->image), true); ?> + + +
    + + + pagination->orderUpIcon($i, true, 'languages.orderup', 'JLIB_HTML_MOVE_UP', $ordering); ?>pagination->orderDownIcon($i, $this->pagination->total, true, 'languages.orderdown', 'JLIB_HTML_MOVE_DOWN', $ordering); ?> + + pagination->orderUpIcon($i, true, 'languages.orderdown', 'JLIB_HTML_MOVE_UP', $ordering); ?>pagination->orderDownIcon($i, $this->pagination->total, true, 'languages.orderup', 'JLIB_HTML_MOVE_DOWN', $ordering); ?> + + + + "; endif;?> class="width-20 text-area-order" /> +
    + + ordering; ?> + +
    + escape($item->access_level); ?> + + home == '1') : ?> + + + + + + escape($item->lang_id); ?> +
    + + + + + + +
    + diff --git a/administrator/components/com_languages/views/languages/tmpl/index.html b/administrator/components/com_languages/views/languages/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/views/languages/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/views/languages/view.html.php b/administrator/components/com_languages/views/languages/view.html.php new file mode 100644 index 0000000..725a6cb --- /dev/null +++ b/administrator/components/com_languages/views/languages/view.html.php @@ -0,0 +1,119 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + LanguagesHelper::addSubmenu('languages'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + require_once JPATH_COMPONENT.'/helpers/languages.php'; + $canDo = LanguagesHelper::getActions(); + + JToolbarHelper::title(JText::_('COM_LANGUAGES_VIEW_LANGUAGES_TITLE'), 'langmanager.png'); + + if ($canDo->get('core.create')) + { + JToolbarHelper::addNew('language.add'); + } + + if ($canDo->get('core.edit')) + { + JToolbarHelper::editList('language.edit'); + JToolbarHelper::divider(); + } + + if ($canDo->get('core.edit.state')) + { + if ($this->state->get('filter.published') != 2) + { + JToolbarHelper::publishList('languages.publish'); + JToolbarHelper::unpublishList('languages.unpublish'); + } + } + + if ($this->state->get('filter.published') == -2 && $canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'languages.delete', 'JTOOLBAR_EMPTY_TRASH'); + JToolbarHelper::divider(); + } elseif ($canDo->get('core.edit.state')) + { + JToolbarHelper::trash('languages.trash'); + JToolbarHelper::divider(); + } + + if ($canDo->get('core.admin')) + { + // Add install languages link to the lang installer component + $bar = JToolbar::getInstance('toolbar'); + $bar->appendButton('Link', 'upload', 'COM_LANGUAGES_INSTALL', 'index.php?option=com_installer&view=languages'); + JToolbarHelper::divider(); + + JToolbarHelper::preferences('com_languages'); + JToolbarHelper::divider(); + } + + JToolbarHelper::help('JHELP_EXTENSIONS_LANGUAGE_MANAGER_CONTENT'); + + JHtmlSidebar::setAction('index.php?option=com_languages&view=languages'); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_published', + JHtml::_('select.options', JHtml::_('jgrid.publishedOptions'), 'value', 'text', $this->state->get('filter.published'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_ACCESS'), + 'filter_access', + JHtml::_('select.options', JHtml::_('access.assetgroups'), 'value', 'text', $this->state->get('filter.access')) + ); + } +} diff --git a/administrator/components/com_languages/views/multilangstatus/index.html b/administrator/components/com_languages/views/multilangstatus/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/views/multilangstatus/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/views/multilangstatus/tmpl/default.php b/administrator/components/com_languages/views/multilangstatus/tmpl/default.php new file mode 100644 index 0000000..f534b11 --- /dev/null +++ b/administrator/components/com_languages/views/multilangstatus/tmpl/default.php @@ -0,0 +1,227 @@ +homes == 2 || $this->homes == 1 || $this->homes - 1 != count($this->contentlangs) && ($this->language_filter || $this->switchers != 0); +$notice_disabled = !$this->language_filter && ($this->homes > 1 || $this->switchers != 0); +$notice_switchers = !$this->switchers && ($this->homes > 1 || $this->language_filter); +?> +
    + language_filter && $this->switchers == 0) : ?> + homes == 1) : ?> +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + contentlangs as $contentlang) : ?> + lang_code, $this->homepages) && (!array_key_exists($contentlang->lang_code, $this->site_langs) || !$contentlang->published)) : ?> + + + + + + + listUsersError) : ?> + + + + + + +
    + + + +
    + + + +
    + + + +
    + + + lang_code); ?> +
    + + + +
      + listUsersError as $user) : ?> +
    • + name); ?> +
    • + +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + language_filter) : ?> + + + + +
    + + + switchers != 0) : ?> + switchers; ?> + + + +
    + homes > 1) : ?> + + + + + + homes > 1) : ?> + homes; ?> + + + +
    + + + + + + + + + + + statuses as $status) : ?> + element) : ?> + + + + element) : // Published Site languages ?> + + + + + lang_code && $status->published) : // Published Content languages ?> + + + + + home_language) : // Published Home pages ?> + + + + + + + contentlangs as $contentlang) : ?> + lang_code, $this->site_langs)) : ?> + + + + + + + + + +
    + + + + + + + +
    + element; ?> + + + + + + + + + + + + +
    + lang_code; ?> + + + + published) : ?> + + published && array_key_exists($contentlang->lang_code, $this->homepages)) : ?> + + published) : ?> + + + + lang_code, $this->homepages)) : ?> + + + + +
    + +
    diff --git a/administrator/components/com_languages/views/multilangstatus/tmpl/index.html b/administrator/components/com_languages/views/multilangstatus/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/views/multilangstatus/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/views/multilangstatus/view.html.php b/administrator/components/com_languages/views/multilangstatus/view.html.php new file mode 100644 index 0000000..ce500c7 --- /dev/null +++ b/administrator/components/com_languages/views/multilangstatus/view.html.php @@ -0,0 +1,39 @@ +homes = MultilangstatusHelper::getHomes(); + $this->language_filter = JLanguageMultilang::isEnabled(); + $this->switchers = MultilangstatusHelper::getLangswitchers(); + $this->listUsersError = MultilangstatusHelper::getContacts(); + $this->contentlangs = MultilangstatusHelper::getContentlangs(); + $this->site_langs = MultilangstatusHelper::getSitelangs(); + $this->statuses = MultilangstatusHelper::getStatus(); + $this->homepages = MultilangstatusHelper::getHomepages(); + + parent::display($tpl); + } +} diff --git a/administrator/components/com_languages/views/override/index.html b/administrator/components/com_languages/views/override/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/views/override/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/views/override/tmpl/edit.php b/administrator/components/com_languages/views/override/tmpl/edit.php new file mode 100644 index 0000000..e046038 --- /dev/null +++ b/administrator/components/com_languages/views/override/tmpl/edit.php @@ -0,0 +1,147 @@ + + + +
    +
    +
    +
    + item->key) ? JText::_('COM_LANGUAGES_VIEW_OVERRIDE_EDIT_NEW_OVERRIDE_LEGEND') : JText::_('COM_LANGUAGES_VIEW_OVERRIDE_EDIT_EDIT_OVERRIDE_LEGEND'); ?> +
    +
    + form->getLabel('key'); ?> +
    +
    + form->getInput('key'); ?> +
    +
    + +
    +
    + form->getLabel('override'); ?> +
    +
    + form->getInput('override'); ?> +
    +
    + + state->get('filter.client') == 'administrator') : ?> +
    +
    + form->getLabel('both'); ?> +
    +
    + form->getInput('both'); ?> +
    +
    + + +
    +
    + form->getLabel('language'); ?> +
    +
    + form->getInput('language'); ?> +
    +
    + +
    +
    + form->getLabel('client'); ?> +
    +
    + form->getInput('client'); ?> +
    +
    + +
    +
    + form->getLabel('file'); ?> +
    +
    + form->getInput('file'); ?> +
    +
    +
    + +
    + +
    +
    + + +

    + +
    + form->getInput('searchstring'); ?> + + + + +
    +
    +
    + form->getLabel('searchtype'); ?> +
    +
    + form->getInput('searchtype'); ?> +
    +
    + +
    + +
    + + + + + +
    + + + + + +
    +
    +
    diff --git a/administrator/components/com_languages/views/override/tmpl/index.html b/administrator/components/com_languages/views/override/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_languages/views/override/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_languages/views/override/view.html.php b/administrator/components/com_languages/views/override/view.html.php new file mode 100644 index 0000000..69c2180 --- /dev/null +++ b/administrator/components/com_languages/views/override/view.html.php @@ -0,0 +1,124 @@ +form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + + // Check for errors + if (count($errors = $this->get('Errors'))) + { + throw new Exception(implode("\n", $errors)); + } + + // Check whether the cache has to be refreshed + $cached_time = JFactory::getApplication()->getUserState('com_languages.overrides.cachedtime.'.$this->state->get('filter.client').'.'.$this->state->get('filter.language'), 0); + if (time() - $cached_time > 60 * 5) + { + $this->state->set('cache_expired', true); + } + + // Add strings for translations in Javascript + JText::script('COM_LANGUAGES_VIEW_OVERRIDE_NO_RESULTS'); + JText::script('COM_LANGUAGES_VIEW_OVERRIDE_REQUEST_ERROR'); + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Adds the page title and toolbar + * + * @return void + * + * @since 2.5 + */ + protected function addToolbar() + { + JFactory::getApplication()->input->set('hidemainmenu', true); + + $canDo = LanguagesHelper::getActions(); + + JToolbarHelper::title(JText::_('COM_LANGUAGES_VIEW_OVERRIDE_EDIT_TITLE'), 'langmanager'); + + if ($canDo->get('core.edit')) + { + JToolbarHelper::apply('override.apply'); + JToolbarHelper::save('override.save'); + } + + // This component does not support Save as Copy + + if ($canDo->get('core.edit') && $canDo->get('core.create')) + { + JToolbarHelper::save2new('override.save2new'); + } + + if (empty($this->item->key)) + { + JToolbarHelper::cancel('override.cancel'); + } + else + { + JToolbarHelper::cancel('override.cancel', 'JTOOLBAR_CLOSE'); + } + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_EXTENSIONS_LANGUAGE_MANAGER_OVERRIDES_EDIT'); + } +} diff --git a/administrator/components/com_languages/views/overrides/index.html b/administrator/components/com_languages/views/overrides/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_languages/views/overrides/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_languages/views/overrides/tmpl/default.php b/administrator/components/com_languages/views/overrides/tmpl/default.php new file mode 100644 index 0000000..75df1d3 --- /dev/null +++ b/administrator/components/com_languages/views/overrides/tmpl/default.php @@ -0,0 +1,102 @@ +state->get('filter.client') == 'site' ? JText::_('JSITE') : JText::_('JADMINISTRATOR'); +$language = $this->state->get('filter.language'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); ?> +
    +sidebar)) : ?> +
    + sidebar; ?> +
    +
    + +
    + +
    + +
    + + +
    +
    + + + + + + + + + + + + + + + + + + authorise('core.edit', 'com_languages'); + $i = 0; + foreach ($this->items as $key => $text) : ?> + + + + + + + + + +
    + + + + + + + + + +
    + pagination->getListFooter(); ?> +
    + + + + escape($key); ?> + + escape($key); ?> + + + escape($text); ?> + + + + +
    + + + + + + +
    + diff --git a/administrator/components/com_languages/views/overrides/tmpl/index.html b/administrator/components/com_languages/views/overrides/tmpl/index.html new file mode 100644 index 0000000..3af6301 --- /dev/null +++ b/administrator/components/com_languages/views/overrides/tmpl/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_languages/views/overrides/view.html.php b/administrator/components/com_languages/views/overrides/view.html.php new file mode 100644 index 0000000..9497cfe --- /dev/null +++ b/administrator/components/com_languages/views/overrides/view.html.php @@ -0,0 +1,121 @@ +state = $this->get('State'); + $this->items = $this->get('Overrides'); + $this->languages = $this->get('Languages'); + $this->pagination = $this->get('Pagination'); + + LanguagesHelper::addSubmenu('overrides'); + + // Check for errors + if (count($errors = $this->get('Errors'))) + { + throw new Exception(implode("\n", $errors)); + } + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Adds the page title and toolbar + * + * @return void + * + * @since 2.5 + */ + protected function addToolbar() + { + // Get the results for each action + $canDo = LanguagesHelper::getActions(); + + JToolbarHelper::title(JText::_('COM_LANGUAGES_VIEW_OVERRIDES_TITLE'), 'langmanager'); + + if ($canDo->get('core.create')) + { + JToolbarHelper::addNew('override.add'); + } + + if ($canDo->get('core.edit') && $this->pagination->total) + { + JToolbarHelper::editList('override.edit'); + } + + if ($canDo->get('core.delete') && $this->pagination->total) + { + JToolbarHelper::deleteList('', 'overrides.delete'); + } + + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_languages'); + } + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_EXTENSIONS_LANGUAGE_MANAGER_OVERRIDES'); + + JHtmlSidebar::setAction('index.php?option=com_languages&view=overrides'); + + JHtmlSidebar::addFilter( + // @todo need a label here + '', + 'filter_language_client', + JHtml::_('select.options', $this->languages, null, 'text', $this->state->get('filter.language_client')), + true + ); + + $this->sidebar = JHtmlSidebar::render(); + } +} diff --git a/administrator/components/com_login/controller.php b/administrator/components/com_login/controller.php new file mode 100644 index 0000000..c029b65 --- /dev/null +++ b/administrator/components/com_login/controller.php @@ -0,0 +1,98 @@ +input->set('view', 'login'); + $this->input->set('layout', 'default'); + + parent::display(); + } + + /** + * Method to log in a user. + * + * @return void + */ + public function login() + { + // Check for request forgeries. + JSession::checkToken('request') or jexit(JText::_('JINVALID_TOKEN')); + + $app = JFactory::getApplication(); + + $model = $this->getModel('login'); + $credentials = $model->getState('credentials'); + $return = $model->getState('return'); + + $result = $app->login($credentials, array('action' => 'core.login.admin')); + + if (!($result instanceof Exception)) + { + $app->redirect($return); + } + + parent::display(); + } + + /** + * Method to log out a user. + * + * @return void + */ + public function logout() + { + JSession::checkToken('request') or jexit(JText::_('JInvalid_Token')); + + $app = JFactory::getApplication(); + + $userid = $this->input->getInt('uid', null); + + $options = array( + 'clientid' => ($userid) ? 0 : 1 + ); + + $result = $app->logout($userid, $options); + + if (!($result instanceof Exception)) + { + $model = $this->getModel('login'); + $return = $model->getState('return'); + $app->redirect($return); + } + + parent::display(); + } +} diff --git a/administrator/components/com_login/index.html b/administrator/components/com_login/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_login/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_login/login.php b/administrator/components/com_login/login.php new file mode 100644 index 0000000..8296f99 --- /dev/null +++ b/administrator/components/com_login/login.php @@ -0,0 +1,22 @@ +input; +$task = $input->get('task'); +if ($task != 'login' && $task != 'logout') +{ + $input->set('task', ''); + $task = ''; +} + +$controller = JControllerLegacy::getInstance('Login'); +$controller->execute($task); +$controller->redirect(); diff --git a/administrator/components/com_login/login.xml b/administrator/components/com_login/login.xml new file mode 100644 index 0000000..d407f8d --- /dev/null +++ b/administrator/components/com_login/login.xml @@ -0,0 +1,26 @@ + + + com_login + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_LOGIN_XML_DESCRIPTION + + + controller.php + index.html + login.php + views + models + + + language/en-GB.com_login.ini + language/en-GB.com_login.sys.ini + + + + diff --git a/administrator/components/com_login/models/index.html b/administrator/components/com_login/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_login/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_login/models/login.php b/administrator/components/com_login/models/login.php new file mode 100644 index 0000000..4af0d46 --- /dev/null +++ b/administrator/components/com_login/models/login.php @@ -0,0 +1,172 @@ + JRequest::getVar('username', '', 'method', 'username'), + 'password' => JRequest::getVar('passwd', '', 'post', 'string', JREQUEST_ALLOWRAW) + ); + $this->setState('credentials', $credentials); + + // check for return URL from the request first + if ($return = JRequest::getVar('return', '', 'method', 'base64')) + { + $return = base64_decode($return); + if (!JUri::isInternal($return)) + { + $return = ''; + } + } + + // Set the return URL if empty. + if (empty($return)) + { + $return = 'index.php'; + } + + $this->setState('return', $return); + } + + /** + * Get the administrator login module by name (real, eg 'login' or folder, eg 'mod_login') + * + * @param string $name The name of the module + * @param string $title The title of the module, optional + * + * @return object The Module object + * + * @since 11.1 + */ + public static function getLoginModule($name = 'mod_login', $title = null) + { + $result = null; + $modules = self::_load($name); + $total = count($modules); + + for ($i = 0; $i < $total; $i++) + { + // Match the title if we're looking for a specific instance of the module + if (!$title || $modules[$i]->title == $title) + { + $result = $modules[$i]; + break; // Found it + } + } + + // If we didn't find it, and the name is mod_something, create a dummy object + if (is_null($result) && substr($name, 0, 4) == 'mod_') + { + $result = new stdClass; + $result->id = 0; + $result->title = ''; + $result->module = $name; + $result->position = ''; + $result->content = ''; + $result->showtitle = 0; + $result->control = ''; + $result->params = ''; + $result->user = 0; + } + + return $result; + } + + /** + * Load login modules. + * + * Note that we load regardless of state or access level since access + * for public is the only thing that makes sense since users are not logged in + * and the module lets them log in. + * This is put in as a failsafe to avoid super user lock out caused by an unpublished + * login module or by a module set to have a viewing access level that is not Public. + * + * @param string $name The name of the module + * + * @return array + * + * @since 11.1 + */ + protected static function _load($module) + { + static $clean; + + if (isset($clean)) + { + return $clean; + } + + $app = JFactory::getApplication(); + $lang = JFactory::getLanguage()->getTag(); + $clientId = (int) $app->getClientId(); + + $cache = JFactory::getCache('com_modules', ''); + $cacheid = md5(serialize(array($clientId, $lang))); + $loginmodule = array(); + + if (!($clean = $cache->get($cacheid))) + { + $db = JFactory::getDbo(); + + $query = $db->getQuery(true) + ->select('m.id, m.title, m.module, m.position, m.showtitle, m.params') + ->from('#__modules AS m') + ->where('m.module =' . $db->quote($module) . ' AND m.client_id = 1') + + ->join('LEFT', '#__extensions AS e ON e.element = m.module AND e.client_id = m.client_id') + ->where('e.enabled = 1'); + + // Filter by language + if ($app->isSite() && $app->getLanguageFilter()) + { + $query->where('m.language IN (' . $db->quote($lang) . ',' . $db->quote('*') . ')'); + } + + $query->order('m.position, m.ordering'); + + // Set the query + $db->setQuery($query); + + try + { + $modules = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, JText::sprintf('JLIB_APPLICATION_ERROR_MODULE_LOAD', $e->getMessage())); + return $loginmodule; + } + + // Return to simple indexing that matches the query order. + $loginmodule = $modules; + + $cache->store($loginmodule, $cacheid); + } + + return $loginmodule; + } +} diff --git a/administrator/components/com_login/views/index.html b/administrator/components/com_login/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_login/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_login/views/login/index.html b/administrator/components/com_login/views/login/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_login/views/login/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_login/views/login/tmpl/default.php b/administrator/components/com_login/views/login/tmpl/default.php new file mode 100644 index 0000000..a382867 --- /dev/null +++ b/administrator/components/com_login/views/login/tmpl/default.php @@ -0,0 +1,31 @@ + 'rounded', 'id' => 'section-box')); + + +//Get any other modules in the login position. +//If you want to use a different position for the modules, change the name here in your override. +$modules = JModuleHelper::getModules('login'); + +foreach ($modules as $module) +// Render the login modules + +if ($module->module != 'mod_login'){ + echo JModuleHelper::renderModule($module, array('style' => 'rounded', 'id' => 'section-box')); +} diff --git a/administrator/components/com_login/views/login/tmpl/index.html b/administrator/components/com_login/views/login/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_login/views/login/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_login/views/login/view.html.php b/administrator/components/com_login/views/login/view.html.php new file mode 100644 index 0000000..864be40 --- /dev/null +++ b/administrator/components/com_login/views/login/view.html.php @@ -0,0 +1,21 @@ + + +
    + + + + +
    +
    diff --git a/administrator/components/com_media/config.xml b/administrator/components/com_media/config.xml new file mode 100644 index 0000000..1ac0225 --- /dev/null +++ b/administrator/components/com_media/config.xml @@ -0,0 +1,121 @@ + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    +
    diff --git a/administrator/components/com_media/controller.php b/administrator/components/com_media/controller.php new file mode 100644 index 0000000..66c8263 --- /dev/null +++ b/administrator/components/com_media/controller.php @@ -0,0 +1,91 @@ +input->get('view', 'media'); + switch ($vName) + { + case 'images': + $vLayout = $this->input->get('layout', 'default'); + $mName = 'manager'; + + break; + + case 'imagesList': + $mName = 'list'; + $vLayout = $this->input->get('layout', 'default'); + + break; + + case 'mediaList': + $app = JFactory::getApplication(); + $mName = 'list'; + $vLayout = $app->getUserStateFromRequest('media.list.layout', 'layout', 'thumbs', 'word'); + + break; + + case 'media': + default: + $vName = 'media'; + $vLayout = $this->input->get('layout', 'default'); + $mName = 'manager'; + break; + } + + $document = JFactory::getDocument(); + $vType = $document->getType(); + + // Get/Create the view + $view = $this->getView($vName, $vType); + $view->addTemplatePath(JPATH_COMPONENT_ADMINISTRATOR.'/views/'.strtolower($vName).'/tmpl'); + + // Get/Create the model + if ($model = $this->getModel($mName)) + { + // Push the model into the view (as default) + $view->setModel($model, true); + } + + // Set the layout + $view->setLayout($vLayout); + + // Display the view + $view->display(); + + return $this; + } + + public function ftpValidate() + { + // Set FTP credentials, if given + JClientHelper::setCredentialsFromRequest('ftp'); + } +} diff --git a/administrator/components/com_media/controllers/file.json.php b/administrator/components/com_media/controllers/file.json.php new file mode 100644 index 0000000..504fa9d --- /dev/null +++ b/administrator/components/com_media/controllers/file.json.php @@ -0,0 +1,182 @@ + '0', + 'error' => JText::_('JINVALID_TOKEN') + ); + echo json_encode($response); + return; + } + + // Get the user + $user = JFactory::getUser(); + JLog::addLogger(array('text_file' => 'upload.error.php'), JLog::ALL, array('upload')); + + // Get some data from the request + $file = $this->input->files->get('Filedata', '', 'array'); + $folder = $this->input->get('folder', '', 'path'); + + if ( + $_SERVER['CONTENT_LENGTH'] > ($params->get('upload_maxsize', 0) * 1024 * 1024) || + $_SERVER['CONTENT_LENGTH'] > (int) (ini_get('upload_max_filesize')) * 1024 * 1024 || + $_SERVER['CONTENT_LENGTH'] > (int) (ini_get('post_max_size')) * 1024 * 1024 || + $_SERVER['CONTENT_LENGTH'] > (int) (ini_get('memory_limit')) * 1024 * 1024 + ) + { + $response = array( + 'status' => '0', + 'error' => JText::_('COM_MEDIA_ERROR_WARNFILETOOLARGE') + ); + echo json_encode($response); + return; + } + + // Set FTP credentials, if given + JClientHelper::setCredentialsFromRequest('ftp'); + + // Make the filename safe + $file['name'] = JFile::makeSafe($file['name']); + + if (isset($file['name'])) + { + // The request is valid + $err = null; + + $filepath = JPath::clean(COM_MEDIA_BASE . '/' . $folder . '/' . strtolower($file['name'])); + + if (!MediaHelper::canUpload($file, $err)) + { + JLog::add('Invalid: ' . $filepath . ': ' . $err, JLog::INFO, 'upload'); + + $response = array( + 'status' => '0', + 'error' => JText::_($err) + ); + + echo json_encode($response); + return; + } + + // Trigger the onContentBeforeSave event. + JPluginHelper::importPlugin('content'); + $dispatcher = JEventDispatcher::getInstance(); + $object_file = new JObject($file); + $object_file->filepath = $filepath; + $result = $dispatcher->trigger('onContentBeforeSave', array('com_media.file', &$object_file, true)); + + if (in_array(false, $result, true)) + { + // There are some errors in the plugins + JLog::add('Errors before save: ' . $object_file->filepath . ' : ' . implode(', ', $object_file->getErrors()), JLog::INFO, 'upload'); + + $response = array( + 'status' => '0', + 'error' => JText::plural('COM_MEDIA_ERROR_BEFORE_SAVE', count($errors = $object_file->getErrors()), implode('
    ', $errors)) + ); + + echo json_encode($response); + return; + } + + if (JFile::exists($object_file->filepath)) + { + // File exists + JLog::add('File exists: ' . $object_file->filepath . ' by user_id ' . $user->id, JLog::INFO, 'upload'); + + $response = array( + 'status' => '0', + 'error' => JText::_('COM_MEDIA_ERROR_FILE_EXISTS') + ); + + echo json_encode($response); + return; + } + elseif (!$user->authorise('core.create', 'com_media')) + { + // File does not exist and user is not authorised to create + JLog::add('Create not permitted: ' . $object_file->filepath . ' by user_id ' . $user->id, JLog::INFO, 'upload'); + + $response = array( + 'status' => '0', + 'error' => JText::_('COM_MEDIA_ERROR_CREATE_NOT_PERMITTED') + ); + + echo json_encode($response); + return; + } + + if (!JFile::upload($object_file->tmp_name, $object_file->filepath)) + { + // Error in upload + JLog::add('Error on upload: ' . $object_file->filepath, JLog::INFO, 'upload'); + + $response = array( + 'status' => '0', + 'error' => JText::_('COM_MEDIA_ERROR_UNABLE_TO_UPLOAD_FILE') + ); + + echo json_encode($response); + return; + } + else + { + // Trigger the onContentAfterSave event. + $dispatcher->trigger('onContentAfterSave', array('com_media.file', &$object_file, true)); + JLog::add($folder, JLog::INFO, 'upload'); + + $response = array( + 'status' => '1', + 'error' => JText::sprintf('COM_MEDIA_UPLOAD_COMPLETE', substr($object_file->filepath, strlen(COM_MEDIA_BASE))) + ); + + echo json_encode($response); + return; + } + } + else + { + $response = array( + 'status' => '0', + 'error' => JText::_('COM_MEDIA_ERROR_BAD_REQUEST') + ); + + echo json_encode($response); + return; + } + } +} diff --git a/administrator/components/com_media/controllers/file.php b/administrator/components/com_media/controllers/file.php new file mode 100644 index 0000000..7677750 --- /dev/null +++ b/administrator/components/com_media/controllers/file.php @@ -0,0 +1,278 @@ +input->files->get('Filedata', '', 'array'); + $return = $this->input->post->get('return-url', null, 'base64'); + $this->folder = $this->input->get('folder', '', 'path'); + + // Set the redirect + if ($return) + { + $this->setRedirect(base64_decode($return) . '&folder=' . $this->folder); + } + + // Authorize the user + if (!$this->authoriseUser('create')) + { + return false; + } + if ( + $_SERVER['CONTENT_LENGTH'] > ($params->get('upload_maxsize', 0) * 1024 * 1024) || + $_SERVER['CONTENT_LENGTH'] > (int) (ini_get('upload_max_filesize')) * 1024 * 1024 || + $_SERVER['CONTENT_LENGTH'] > (int) (ini_get('post_max_size')) * 1024 * 1024 || + (($_SERVER['CONTENT_LENGTH'] > (int) (ini_get('memory_limit')) * 1024 * 1024) && ((int) (ini_get('memory_limit')) != -1)) + ) + { + JError::raiseWarning(100, JText::_('COM_MEDIA_ERROR_WARNFILETOOLARGE')); + return false; + } + + // Perform basic checks on file info before attempting anything + foreach ($files as &$file) + { + $file['name'] = JFile::makeSafe($file['name']); + $file['filepath'] = JPath::clean(implode(DIRECTORY_SEPARATOR, array(COM_MEDIA_BASE, $this->folder, $file['name']))); + + if ($file['error'] == 1) + { + JError::raiseWarning(100, JText::_('COM_MEDIA_ERROR_WARNFILETOOLARGE')); + return false; + } + + if ($file['size'] > ($params->get('upload_maxsize', 0) * 1024 * 1024)) + { + JError::raiseNotice(100, JText::_('COM_MEDIA_ERROR_WARNFILETOOLARGE')); + return false; + } + + if (JFile::exists($file['filepath'])) + { + // A file with this name already exists + JError::raiseWarning(100, JText::_('COM_MEDIA_ERROR_FILE_EXISTS')); + return false; + } + + if (!isset($file['name'])) + { + // No filename (after the name was cleaned by JFile::makeSafe) + $this->setRedirect('index.php', JText::_('COM_MEDIA_INVALID_REQUEST'), 'error'); + return false; + } + } + + // Set FTP credentials, if given + JClientHelper::setCredentialsFromRequest('ftp'); + JPluginHelper::importPlugin('content'); + $dispatcher = JEventDispatcher::getInstance(); + + foreach ($files as &$file) + { + // The request is valid + $err = null; + + if (!MediaHelper::canUpload($file, $err)) + { + // The file can't be upload + JError::raiseNotice(100, JText::_($err)); + return false; + } + + // Trigger the onContentBeforeSave event. + $object_file = new JObject($file); + $result = $dispatcher->trigger('onContentBeforeSave', array('com_media.file', &$object_file, true)); + + if (in_array(false, $result, true)) + { + // There are some errors in the plugins + JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_SAVE', count($errors = $object_file->getErrors()), implode('
    ', $errors))); + return false; + } + + if (!JFile::upload($object_file->tmp_name, $object_file->filepath)) + { + // Error in upload + JError::raiseWarning(100, JText::_('COM_MEDIA_ERROR_UNABLE_TO_UPLOAD_FILE')); + return false; + } + else + { + // Trigger the onContentAfterSave event. + $dispatcher->trigger('onContentAfterSave', array('com_media.file', &$object_file, true)); + $this->setMessage(JText::sprintf('COM_MEDIA_UPLOAD_COMPLETE', substr($object_file->filepath, strlen(COM_MEDIA_BASE)))); + } + } + + return true; + } + + /** + * Check that the user is authorized to perform this action + * + * @param string $action - the action to be peformed (create or delete) + * + * @return boolean + * + * @since 1.6 + */ + protected function authoriseUser($action) + { + if (!JFactory::getUser()->authorise('core.' . strtolower($action), 'com_media')) + { + // User is not authorised + JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_' . strtoupper($action) . '_NOT_PERMITTED')); + return false; + } + + return true; + } + + /** + * Deletes paths from the current path + * + * @return boolean + * + * @since 1.5 + */ + public function delete() + { + JSession::checkToken('request') or jexit(JText::_('JINVALID_TOKEN')); + + // Get some data from the request + $tmpl = $this->input->get('tmpl'); + $paths = $this->input->get('rm', array(), 'array'); + $folder = $this->input->get('folder', '', 'path'); + + $redirect = 'index.php?option=com_media&folder=' . $folder; + + if ($tmpl == 'component') + { + // We are inside the iframe + $redirect .= '&view=mediaList&tmpl=component'; + } + + $this->setRedirect($redirect); + + // Nothing to delete + if (empty($paths)) + { + return true; + } + + // Authorize the user + if (!$this->authoriseUser('delete')) + { + return false; + } + + // Set FTP credentials, if given + JClientHelper::setCredentialsFromRequest('ftp'); + + JPluginHelper::importPlugin('content'); + $dispatcher = JEventDispatcher::getInstance(); + + $ret = true; + + foreach ($paths as $path) + { + if ($path !== JFile::makeSafe($path)) + { + // filename is not safe + $filename = htmlspecialchars($path, ENT_COMPAT, 'UTF-8'); + JError::raiseWarning(100, JText::sprintf('COM_MEDIA_ERROR_UNABLE_TO_DELETE_FILE_WARNFILENAME', substr($filename, strlen(COM_MEDIA_BASE)))); + continue; + } + + $fullPath = JPath::clean(implode(DIRECTORY_SEPARATOR, array(COM_MEDIA_BASE, $folder, $path))); + $object_file = new JObject(array('filepath' => $fullPath)); + + if (is_file($object_file->filepath)) + { + // Trigger the onContentBeforeDelete event. + $result = $dispatcher->trigger('onContentBeforeDelete', array('com_media.file', &$object_file)); + if (in_array(false, $result, true)) + { + // There are some errors in the plugins + JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_DELETE', count($errors = $object_file->getErrors()), implode('
    ', $errors))); + continue; + } + + $ret &= JFile::delete($object_file->filepath); + + // Trigger the onContentAfterDelete event. + $dispatcher->trigger('onContentAfterDelete', array('com_media.file', &$object_file)); + $this->setMessage(JText::sprintf('COM_MEDIA_DELETE_COMPLETE', substr($object_file->filepath, strlen(COM_MEDIA_BASE)))); + } + elseif (is_dir($object_file->filepath)) + { + $contents = JFolder::files($object_file->filepath, '.', true, false, array('.svn', 'CVS', '.DS_Store', '__MACOSX', 'index.html')); + + if (empty($contents)) + { + // Trigger the onContentBeforeDelete event. + $result = $dispatcher->trigger('onContentBeforeDelete', array('com_media.folder', &$object_file)); + + if (in_array(false, $result, true)) + { + // There are some errors in the plugins + JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_DELETE', count($errors = $object_file->getErrors()), implode('
    ', $errors))); + continue; + } + + $ret &= JFolder::delete($object_file->filepath); + + // Trigger the onContentAfterDelete event. + $dispatcher->trigger('onContentAfterDelete', array('com_media.folder', &$object_file)); + $this->setMessage(JText::sprintf('COM_MEDIA_DELETE_COMPLETE', substr($object_file->filepath, strlen(COM_MEDIA_BASE)))); + } + else + { + // This makes no sense... + JError::raiseWarning(100, JText::sprintf('COM_MEDIA_ERROR_UNABLE_TO_DELETE_FOLDER_NOT_EMPTY', substr($object_file->filepath, strlen(COM_MEDIA_BASE)))); + } + } + } + + return $ret; + } +} diff --git a/administrator/components/com_media/controllers/folder.php b/administrator/components/com_media/controllers/folder.php new file mode 100644 index 0000000..10cc807 --- /dev/null +++ b/administrator/components/com_media/controllers/folder.php @@ -0,0 +1,210 @@ +input->get('tmpl'); + $paths = $this->input->get('rm', array(), 'array'); + $folder = $this->input->get('folder', '', 'path'); + + $redirect = 'index.php?option=com_media&folder=' . $folder; + + if ($tmpl == 'component') + { + // We are inside the iframe + $redirect .= '&view=mediaList&tmpl=component'; + } + + $this->setRedirect($redirect); + + // Just return if there's nothing to do + if (empty($paths)) + { + return true; + } + + if (!$user->authorise('core.delete', 'com_media')) + { + // User is not authorised to delete + JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED')); + return false; + } + + // Set FTP credentials, if given + JClientHelper::setCredentialsFromRequest('ftp'); + + $ret = true; + + JPluginHelper::importPlugin('content'); + $dispatcher = JEventDispatcher::getInstance(); + + if (count($paths)) + { + foreach ($paths as $path) + { + if ($path !== JFile::makeSafe($path)) + { + $dirname = htmlspecialchars($path, ENT_COMPAT, 'UTF-8'); + JError::raiseWarning(100, JText::sprintf('COM_MEDIA_ERROR_UNABLE_TO_DELETE_FOLDER_WARNDIRNAME', substr($dirname, strlen(COM_MEDIA_BASE)))); + continue; + } + + $fullPath = JPath::clean(implode(DIRECTORY_SEPARATOR, array(COM_MEDIA_BASE, $folder, $path))); + $object_file = new JObject(array('filepath' => $fullPath)); + + if (is_file($object_file->filepath)) + { + // Trigger the onContentBeforeDelete event. + $result = $dispatcher->trigger('onContentBeforeDelete', array('com_media.file', &$object_file)); + + if (in_array(false, $result, true)) + { + // There are some errors in the plugins + JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_DELETE', count($errors = $object_file->getErrors()), implode('
    ', $errors))); + continue; + } + + $ret &= JFile::delete($object_file->filepath); + + // Trigger the onContentAfterDelete event. + $dispatcher->trigger('onContentAfterDelete', array('com_media.file', &$object_file)); + $this->setMessage(JText::sprintf('COM_MEDIA_DELETE_COMPLETE', substr($object_file->filepath, strlen(COM_MEDIA_BASE)))); + } + elseif (is_dir($object_file->filepath)) + { + $contents = JFolder::files($object_file->filepath, '.', true, false, array('.svn', 'CVS', '.DS_Store', '__MACOSX', 'index.html')); + + if (empty($contents)) + { + // Trigger the onContentBeforeDelete event. + $result = $dispatcher->trigger('onContentBeforeDelete', array('com_media.folder', &$object_file)); + + if (in_array(false, $result, true)) + { + // There are some errors in the plugins + JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_DELETE', count($errors = $object_file->getErrors()), implode('
    ', $errors))); + continue; + } + + $ret &= !JFolder::delete($object_file->filepath); + + // Trigger the onContentAfterDelete event. + $dispatcher->trigger('onContentAfterDelete', array('com_media.folder', &$object_file)); + $this->setMessage(JText::sprintf('COM_MEDIA_DELETE_COMPLETE', substr($object_file->filepath, strlen(COM_MEDIA_BASE)))); + } + else + { + //This makes no sense... + JError::raiseWarning(100, JText::sprintf('COM_MEDIA_ERROR_UNABLE_TO_DELETE_FOLDER_NOT_EMPTY', substr($object_file->filepath, strlen(COM_MEDIA_BASE)))); + } + } + } + } + + return $ret; + } + + /** + * Create a folder + * + * @return boolean + * + * @since 1.5 + */ + public function create() + { + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $user = JFactory::getUser(); + + $folder = $this->input->get('foldername', ''); + $folderCheck = (string) $this->input->get('foldername', null, 'raw'); + $parent = $this->input->get('folderbase', '', 'path'); + + $this->setRedirect('index.php?option=com_media&folder=' . $parent . '&tmpl=' . $this->input->get('tmpl', 'index')); + + if (strlen($folder) > 0) + { + if (!$user->authorise('core.create', 'com_media')) + { + // User is not authorised to delete + JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_CREATE_NOT_PERMITTED')); + return false; + } + + // Set FTP credentials, if given + JClientHelper::setCredentialsFromRequest('ftp'); + + $this->input->set('folder', $parent); + + if (($folderCheck !== null) && ($folder !== $folderCheck)) + { + $this->setMessage(JText::_('COM_MEDIA_ERROR_UNABLE_TO_CREATE_FOLDER_WARNDIRNAME')); + return false; + } + + $path = JPath::clean(COM_MEDIA_BASE . '/' . $parent . '/' . $folder); + + if (!is_dir($path) && !is_file($path)) + { + // Trigger the onContentBeforeSave event. + $object_file = new JObject(array('filepath' => $path)); + JPluginHelper::importPlugin('content'); + $dispatcher = JEventDispatcher::getInstance(); + $result = $dispatcher->trigger('onContentBeforeSave', array('com_media.folder', &$object_file, true)); + + if (in_array(false, $result, true)) + { + // There are some errors in the plugins + JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_SAVE', count($errors = $object_file->getErrors()), implode('
    ', $errors))); + return false; + } + + JFolder::create($object_file->filepath); + $data = "\n\n\n"; + JFile::write($object_file->filepath . "/index.html", $data); + + // Trigger the onContentAfterSave event. + $dispatcher->trigger('onContentAfterSave', array('com_media.folder', &$object_file, true)); + $this->setMessage(JText::sprintf('COM_MEDIA_CREATE_COMPLETE', substr($object_file->filepath, strlen(COM_MEDIA_BASE)))); + } + + $this->input->set('folder', ($parent) ? $parent.'/'.$folder : $folder); + } + + return true; + } +} diff --git a/administrator/components/com_media/controllers/index.html b/administrator/components/com_media/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/helpers/index.html b/administrator/components/com_media/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/helpers/media.php b/administrator/components/com_media/helpers/media.php new file mode 100644 index 0000000..a71f8c3 --- /dev/null +++ b/administrator/components/com_media/helpers/media.php @@ -0,0 +1,212 @@ +get('upload_extensions')); + $ignored = explode(',', $params->get('ignore_extensions')); + if ($format == '' || $format == false || (!in_array($format, $allowable) && !in_array($format, $ignored))) + { + $err = 'COM_MEDIA_ERROR_WARNFILETYPE'; + return false; + } + + $maxSize = (int) ($params->get('upload_maxsize', 0) * 1024 * 1024); + if ($maxSize > 0 && (int) $file['size'] > $maxSize) + { + $err = 'COM_MEDIA_ERROR_WARNFILETOOLARGE'; + return false; + } + + $user = JFactory::getUser(); + $imginfo = null; + if ($params->get('restrict_uploads', 1)) + { + $images = explode(',', $params->get('image_extensions')); + if (in_array($format, $images)) { // if its an image run it through getimagesize + // if tmp_name is empty, then the file was bigger than the PHP limit + if (!empty($file['tmp_name'])) + { + if (($imginfo = getimagesize($file['tmp_name'])) === false) + { + $err = 'COM_MEDIA_ERROR_WARNINVALID_IMG'; + return false; + } + } else { + $err = 'COM_MEDIA_ERROR_WARNFILETOOLARGE'; + return false; + } + } elseif (!in_array($format, $ignored)) + { + // if its not an image...and we're not ignoring it + $allowed_mime = explode(',', $params->get('upload_mime')); + $illegal_mime = explode(',', $params->get('upload_mime_illegal')); + if (function_exists('finfo_open') && $params->get('check_mime', 1)) + { + // We have fileinfo + $finfo = finfo_open(FILEINFO_MIME); + $type = finfo_file($finfo, $file['tmp_name']); + if (strlen($type) && !in_array($type, $allowed_mime) && in_array($type, $illegal_mime)) + { + $err = 'COM_MEDIA_ERROR_WARNINVALID_MIME'; + return false; + } + finfo_close($finfo); + } elseif (function_exists('mime_content_type') && $params->get('check_mime', 1)) + { + // we have mime magic + $type = mime_content_type($file['tmp_name']); + if (strlen($type) && !in_array($type, $allowed_mime) && in_array($type, $illegal_mime)) + { + $err = 'COM_MEDIA_ERROR_WARNINVALID_MIME'; + return false; + } + } elseif (!$user->authorise('core.manage')) + { + $err = 'COM_MEDIA_ERROR_WARNNOTADMIN'; + return false; + } + } + } + + $xss_check = file_get_contents($file['tmp_name'], false, null, -1, 256); + $html_tags = array('abbr', 'acronym', 'address', 'applet', 'area', 'audioscope', 'base', 'basefont', 'bdo', 'bgsound', 'big', 'blackface', 'blink', 'blockquote', 'body', 'bq', 'br', 'button', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'comment', 'custom', 'dd', 'del', 'dfn', 'dir', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'fn', 'font', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'html', 'iframe', 'ilayer', 'img', 'input', 'ins', 'isindex', 'keygen', 'kbd', 'label', 'layer', 'legend', 'li', 'limittext', 'link', 'listing', 'map', 'marquee', 'menu', 'meta', 'multicol', 'nobr', 'noembed', 'noframes', 'noscript', 'nosmartquotes', 'object', 'ol', 'optgroup', 'option', 'param', 'plaintext', 'pre', 'rt', 'ruby', 's', 'samp', 'script', 'select', 'server', 'shadow', 'sidebar', 'small', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'title', 'tr', 'tt', 'ul', 'var', 'wbr', 'xml', 'xmp', '!DOCTYPE', '!--'); + + foreach ($html_tags as $tag) + { + // A tag is '' + if (stristr($xss_check, '<'.$tag.' ') || stristr($xss_check, '<'.$tag.'>')) + { + $err = 'COM_MEDIA_ERROR_WARNIEXSS'; + return false; + } + } + return true; + } + + /** + * Method to parse a file size + * + * @param integer $size The file size in bytes + * + * @return string The converted file size + * + * @since 1.6 + * @deprecated 4.0 Use JHtmlNumber::bytes() instead + */ + public static function parseSize($size) + { + JLog::add('MediaHelper::parseSize() is deprecated. Use JHtmlNumber::bytes() instead.', JLog::WARNING, 'deprecated'); + return JHtml::_('number.bytes', $size); + } + + public static function imageResize($width, $height, $target) + { + //takes the larger size of the width and height and applies the + //formula accordingly...this is so this script will work + //dynamically with any size image + if ($width > $height) + { + $percentage = ($target / $width); + } + else + { + $percentage = ($target / $height); + } + + //gets the new value and applies the percentage, then rounds the value + $width = round($width * $percentage); + $height = round($height * $percentage); + + return array($width, $height); + } + + public static function countFiles($dir) + { + $total_file = 0; + $total_dir = 0; + + if (is_dir($dir)) + { + $d = dir($dir); + + while (false !== ($entry = $d->read())) + { + if (substr($entry, 0, 1) != '.' && is_file($dir . DIRECTORY_SEPARATOR . $entry) && strpos($entry, '.html') === false && strpos($entry, '.php') === false) + { + $total_file++; + } + if (substr($entry, 0, 1) != '.' && is_dir($dir . DIRECTORY_SEPARATOR . $entry)) + { + $total_dir++; + } + } + + $d->close(); + } + + return array ($total_file, $total_dir); + } + +} diff --git a/administrator/components/com_media/index.html b/administrator/components/com_media/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/media.php b/administrator/components/com_media/media.php new file mode 100644 index 0000000..c6551cb --- /dev/null +++ b/administrator/components/com_media/media.php @@ -0,0 +1,48 @@ +input; +$user = JFactory::getUser(); +$asset = $input->get('asset'); +$author = $input->get('author'); + +// Access check. +if (!$user->authorise('core.manage', 'com_media') + && (!$asset or ( + !$user->authorise('core.edit', $asset) + && !$user->authorise('core.create', $asset) + && count($user->getAuthorisedCategories($asset, 'core.create')) == 0) + && !($user->id == $author && $user->authorise('core.edit.own', $asset)))) +{ + return JError::raiseWarning(403, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$params = JComponentHelper::getParams('com_media'); + +// Load the helper class +require_once JPATH_COMPONENT_ADMINISTRATOR . '/helpers/media.php'; + +// Set the path definitions +$popup_upload = $input->get('pop_up', null); +$path = 'file_path'; + +$view = $input->get('view'); +if (substr(strtolower($view), 0, 6) == 'images' || $popup_upload == 1) +{ + $path = 'image_path'; +} + +define('COM_MEDIA_BASE', JPATH_ROOT . '/' . $params->get($path, 'images')); +define('COM_MEDIA_BASEURL', JUri::root() . $params->get($path, 'images')); + +$controller = JControllerLegacy::getInstance('Media', array('base_path' => JPATH_COMPONENT_ADMINISTRATOR)); +$controller->execute($input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_media/media.xml b/administrator/components/com_media/media.xml new file mode 100644 index 0000000..3c76a2d --- /dev/null +++ b/administrator/components/com_media/media.xml @@ -0,0 +1,39 @@ + + + com_media + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_MEDIA_XML_DESCRIPTION + + + controller.php + index.html + media.php + helpers + + + language/en-GB.com_media.ini + + + + config.xml + controller.php + index.html + media.php + controllers + helpers + models + views + + + language/en-GB.com_media.ini + language/en-GB.com_media.sys.ini + + + + diff --git a/administrator/components/com_media/models/forms/index.html b/administrator/components/com_media/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/models/index.html b/administrator/components/com_media/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/models/list.php b/administrator/components/com_media/models/list.php new file mode 100644 index 0000000..0b64b9d --- /dev/null +++ b/administrator/components/com_media/models/list.php @@ -0,0 +1,202 @@ +input; + $folder = $input->get('folder', '', 'path'); + $this->setState('folder', $folder); + + $parent = str_replace("\\", "/", dirname($folder)); + $parent = ($parent == '.') ? null : $parent; + $this->setState('parent', $parent); + $set = true; + } + + return parent::getState($property, $default); + } + + public function getImages() + { + $list = $this->getList(); + + return $list['images']; + } + + public function getFolders() + { + $list = $this->getList(); + + return $list['folders']; + } + + public function getDocuments() + { + $list = $this->getList(); + + return $list['docs']; + } + + /** + * Build imagelist + * + * @param string $listFolder The image directory to display + * @since 1.5 + */ + public function getList() + { + static $list; + + // Only process the list once per request + if (is_array($list)) + { + return $list; + } + + // Get current path from request + $current = $this->getState('folder'); + + // If undefined, set to empty + if ($current == 'undefined') + { + $current = ''; + } + + if (strlen($current) > 0) + { + $basePath = COM_MEDIA_BASE.'/'.$current; + } + else + { + $basePath = COM_MEDIA_BASE; + } + + $mediaBase = str_replace(DIRECTORY_SEPARATOR, '/', COM_MEDIA_BASE.'/'); + + $images = array (); + $folders = array (); + $docs = array (); + + $fileList = false; + $folderList = false; + if (file_exists($basePath)) + { + // Get the list of files and folders from the given folder + $fileList = JFolder::files($basePath); + $folderList = JFolder::folders($basePath); + } + + // Iterate over the files if they exist + if ($fileList !== false) + { + foreach ($fileList as $file) + { + if (is_file($basePath.'/'.$file) && substr($file, 0, 1) != '.' && strtolower($file) !== 'index.html') + { + $tmp = new JObject; + $tmp->name = $file; + $tmp->title = $file; + $tmp->path = str_replace(DIRECTORY_SEPARATOR, '/', JPath::clean($basePath . '/' . $file)); + $tmp->path_relative = str_replace($mediaBase, '', $tmp->path); + $tmp->size = filesize($tmp->path); + + $ext = strtolower(JFile::getExt($file)); + switch ($ext) + { + // Image + case 'jpg': + case 'png': + case 'gif': + case 'xcf': + case 'odg': + case 'bmp': + case 'jpeg': + case 'ico': + $info = @getimagesize($tmp->path); + $tmp->width = @$info[0]; + $tmp->height = @$info[1]; + $tmp->type = @$info[2]; + $tmp->mime = @$info['mime']; + + if (($info[0] > 60) || ($info[1] > 60)) + { + $dimensions = MediaHelper::imageResize($info[0], $info[1], 60); + $tmp->width_60 = $dimensions[0]; + $tmp->height_60 = $dimensions[1]; + } + else { + $tmp->width_60 = $tmp->width; + $tmp->height_60 = $tmp->height; + } + + if (($info[0] > 16) || ($info[1] > 16)) + { + $dimensions = MediaHelper::imageResize($info[0], $info[1], 16); + $tmp->width_16 = $dimensions[0]; + $tmp->height_16 = $dimensions[1]; + } + else { + $tmp->width_16 = $tmp->width; + $tmp->height_16 = $tmp->height; + } + + $images[] = $tmp; + break; + + // Non-image document + default: + $tmp->icon_32 = "media/mime-icon-32/".$ext.".png"; + $tmp->icon_16 = "media/mime-icon-16/".$ext.".png"; + $docs[] = $tmp; + break; + } + } + } + } + + // Iterate over the folders if they exist + if ($folderList !== false) + { + foreach ($folderList as $folder) + { + $tmp = new JObject; + $tmp->name = basename($folder); + $tmp->path = str_replace(DIRECTORY_SEPARATOR, '/', JPath::clean($basePath . '/' . $folder)); + $tmp->path_relative = str_replace($mediaBase, '', $tmp->path); + $count = MediaHelper::countFiles($tmp->path); + $tmp->files = $count[0]; + $tmp->folders = $count[1]; + + $folders[] = $tmp; + } + } + + $list = array('folders' => $folders, 'docs' => $docs, 'images' => $images); + + return $list; + } +} diff --git a/administrator/components/com_media/models/manager.php b/administrator/components/com_media/models/manager.php new file mode 100644 index 0000000..64f171c --- /dev/null +++ b/administrator/components/com_media/models/manager.php @@ -0,0 +1,146 @@ +input; + + $folder = $input->get('folder', '', 'path'); + $this->setState('folder', $folder); + + $fieldid = $input->get('fieldid', ''); + $this->setState('field.id', $fieldid); + + $parent = str_replace("\\", "/", dirname($folder)); + $parent = ($parent == '.') ? null : $parent; + $this->setState('parent', $parent); + $set = true; + } + + return parent::getState($property, $default); + } + + /** + * Image Manager Popup + * + * @param string $listFolder The image directory to display + * @since 1.5 + */ + function getFolderList($base = null) + { + // Get some paths from the request + if (empty($base)) + { + $base = COM_MEDIA_BASE; + } + //corrections for windows paths + $base = str_replace(DIRECTORY_SEPARATOR, '/', $base); + $com_media_base_uni = str_replace(DIRECTORY_SEPARATOR, '/', COM_MEDIA_BASE); + + // Get the list of folders + jimport('joomla.filesystem.folder'); + $folders = JFolder::folders($base, '.', true, true); + + $document = JFactory::getDocument(); + $document->setTitle(JText::_('COM_MEDIA_INSERT_IMAGE')); + + // Build the array of select options for the folder list + $options[] = JHtml::_('select.option', "", "/"); + + foreach ($folders as $folder) + { + $folder = str_replace($com_media_base_uni, "", str_replace(DIRECTORY_SEPARATOR, '/', $folder)); + $value = substr($folder, 1); + $text = str_replace(DIRECTORY_SEPARATOR, "/", $folder); + $options[] = JHtml::_('select.option', $value, $text); + } + + // Sort the folder list array + if (is_array($options)) + { + sort($options); + } + + // Get asset and author id (use integer filter) + $input = JFactory::getApplication()->input; + $asset = $input->get('asset', 0, 'integer'); + $author = $input->get('author', 0, 'integer'); + + // Create the drop-down folder select list + $list = JHtml::_('select.genericlist', $options, 'folderlist', 'class="inputbox" size="1" onchange="ImageManager.setFolder(this.options[this.selectedIndex].value, '.$asset.', '.$author.')" ', 'value', 'text', $base); + + return $list; + } + + function getFolderTree($base = null) + { + // Get some paths from the request + if (empty($base)) + { + $base = COM_MEDIA_BASE; + } + + $mediaBase = str_replace(DIRECTORY_SEPARATOR, '/', COM_MEDIA_BASE.'/'); + + // Get the list of folders + jimport('joomla.filesystem.folder'); + $folders = JFolder::folders($base, '.', true, true); + + $tree = array(); + + foreach ($folders as $folder) + { + $folder = str_replace(DIRECTORY_SEPARATOR, '/', $folder); + $name = substr($folder, strrpos($folder, '/') + 1); + $relative = str_replace($mediaBase, '', $folder); + $absolute = $folder; + $path = explode('/', $relative); + $node = (object) array('name' => $name, 'relative' => $relative, 'absolute' => $absolute); + + $tmp = &$tree; + for ($i = 0, $n = count($path); $i < $n; $i++) + { + if (!isset($tmp['children'])) + { + $tmp['children'] = array(); + } + + if ($i == $n - 1) + { + // We need to place the node + $tmp['children'][$relative] = array('data' => $node, 'children' => array()); + break; + } + + if (array_key_exists($key = implode('/', array_slice($path, 0, $i + 1)), $tmp['children'])) + { + $tmp = &$tmp['children'][$key]; + } + } + } + $tree['data'] = (object) array('name' => JText::_('COM_MEDIA_MEDIA'), 'relative' => '', 'absolute' => $base); + + return $tree; + } +} diff --git a/administrator/components/com_media/views/images/index.html b/administrator/components/com_media/views/images/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/views/images/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/views/images/tmpl/default.php b/administrator/components/com_media/views/images/tmpl/default.php new file mode 100644 index 0000000..48c7a1f --- /dev/null +++ b/administrator/components/com_media/views/images/tmpl/default.php @@ -0,0 +1,130 @@ +input; +?> + +
    + +
    +
    +
    +
    + +
    +
    + folderList; ?> + +
    +
    +
    + + +
    +
    +
    + + + +
    +
    +
    +
    + +
    +
    + +
    +
    + state->get('field.id')):?> +
    +
    + +
    +
    + +

    +
    +
    + +
    + state->get('field.id')):?> +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    + +

    +
    +
    +
    + + + + + + +
    +
    + +authorise('core.create', 'com_media')) : ?> +
    +
    +
    +
    +
    + +
    +
    + +

    config->get('upload_maxsize') == '0' ? JText::_('COM_MEDIA_UPLOAD_FILES_NOLIMIT') : JText::sprintf('COM_MEDIA_UPLOAD_FILES', $this->config->get('upload_maxsize')); ?>

    +
    +
    +
    + +
    +
    + diff --git a/administrator/components/com_media/views/images/tmpl/index.html b/administrator/components/com_media/views/images/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/views/images/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/views/images/view.html.php b/administrator/components/com_media/views/images/view.html.php new file mode 100644 index 0000000..8b26600 --- /dev/null +++ b/administrator/components/com_media/views/images/view.html.php @@ -0,0 +1,49 @@ +isRTL()) + { + JHtml::_('stylesheet', 'media/popup-imagemanager_rtl.css', array(), true); + } + + /* + * Display form for FTP credentials? + * Don't set them here, as there are other functions called before this one if there is any file write operation + */ + $ftp = !JClientHelper::hasCredentials('ftp'); + + $this->session = JFactory::getSession(); + $this->config = $config; + $this->state = $this->get('state'); + $this->folderList = $this->get('folderList'); + $this->require_ftp = $ftp; + + parent::display($tpl); + } +} diff --git a/administrator/components/com_media/views/imageslist/index.html b/administrator/components/com_media/views/imageslist/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/views/imageslist/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/views/imageslist/tmpl/default.php b/administrator/components/com_media/views/imageslist/tmpl/default.php new file mode 100644 index 0000000..bc64053 --- /dev/null +++ b/administrator/components/com_media/views/imageslist/tmpl/default.php @@ -0,0 +1,28 @@ + +images) > 0 || count($this->folders) > 0) { ?> +
      + folders); $i < $n; $i++) : + $this->setFolder($i); + echo $this->loadTemplate('folder'); + endfor; ?> + + images); $i < $n; $i++) : + $this->setImage($i); + echo $this->loadTemplate('image'); + endfor; ?> +
    + +
    +
    +
    + diff --git a/administrator/components/com_media/views/imageslist/tmpl/default_folder.php b/administrator/components/com_media/views/imageslist/tmpl/default_folder.php new file mode 100644 index 0000000..ddecbfc --- /dev/null +++ b/administrator/components/com_media/views/imageslist/tmpl/default_folder.php @@ -0,0 +1,23 @@ +input; +?> +
  • + +
    + +
    +
    + _tmp_folder->name, 10, false); ?> +
    +
    +
  • diff --git a/administrator/components/com_media/views/imageslist/tmpl/default_image.php b/administrator/components/com_media/views/imageslist/tmpl/default_image.php new file mode 100644 index 0000000..440feb0 --- /dev/null +++ b/administrator/components/com_media/views/imageslist/tmpl/default_image.php @@ -0,0 +1,28 @@ +trigger('onContentBeforeDisplay', array('com_media.file', &$this->_tmp_img, &$params)); +?> +
  • + +
    + baseURL . '/' . $this->_tmp_img->path_relative, JText::sprintf('COM_MEDIA_IMAGE_TITLE', $this->_tmp_img->title, JHtml::_('number.bytes', $this->_tmp_img->size)), array('width' => $this->_tmp_img->width_60, 'height' => $this->_tmp_img->height_60)); ?> +
    +
    + _tmp_img->name, 10, false); ?> +
    +
    +
  • +trigger('onContentAfterDisplay', array('com_media.file', &$this->_tmp_img, &$params)); +?> diff --git a/administrator/components/com_media/views/imageslist/tmpl/index.html b/administrator/components/com_media/views/imageslist/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/views/imageslist/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/views/imageslist/view.html.php b/administrator/components/com_media/views/imageslist/view.html.php new file mode 100644 index 0000000..ff3414a --- /dev/null +++ b/administrator/components/com_media/views/imageslist/view.html.php @@ -0,0 +1,71 @@ +isRTL()) { + JHtml::_('stylesheet', 'media/popup-imagelist_rtl.css', array(), true); + } + + $document = JFactory::getDocument(); + $document->addScriptDeclaration("var ImageManager = window.parent.ImageManager;"); + + $images = $this->get('images'); + $folders = $this->get('folders'); + $state = $this->get('state'); + + $this->baseURL = COM_MEDIA_BASEURL; + $this->images = &$images; + $this->folders = &$folders; + $this->state = &$state; + + parent::display($tpl); + } + + function setFolder($index = 0) + { + if (isset($this->folders[$index])) + { + $this->_tmp_folder = &$this->folders[$index]; + } + else + { + $this->_tmp_folder = new JObject; + } + } + + function setImage($index = 0) + { + if (isset($this->images[$index])) + { + $this->_tmp_img = &$this->images[$index]; + } + else + { + $this->_tmp_img = new JObject; + } + } +} diff --git a/administrator/components/com_media/views/index.html b/administrator/components/com_media/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/views/media/index.html b/administrator/components/com_media/views/media/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/views/media/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/views/media/tmpl/default.php b/administrator/components/com_media/views/media/tmpl/default.php new file mode 100644 index 0000000..99b4f1d --- /dev/null +++ b/administrator/components/com_media/views/media/tmpl/default.php @@ -0,0 +1,92 @@ +input; +?> +
    + +
    +
    + +
    +
    + + + +
    + loadTemplate('navigation'); ?> + authorise('core.create', 'com_media')) and $this->require_ftp) : ?> +
    +
    + + + + + + + +
    +
    + + +
    + + + +
    + + authorise('core.create', 'com_media')):?> + +
    +
    +
    +
    + + +

    config->get('upload_maxsize') == '0' ? JText::_('COM_MEDIA_UPLOAD_FILES_NOLIMIT') : JText::sprintf('COM_MEDIA_UPLOAD_FILES', $this->config->get('upload_maxsize')); ?>

    +
    + + +
    +
    +
    +
    +
    +
    + + + + +
    + +
    +
    + + +
    +
    +
    + +
    + +
    +
    +
    + +
    diff --git a/administrator/components/com_media/views/media/tmpl/default_folders.php b/administrator/components/com_media/views/media/tmpl/default_folders.php new file mode 100644 index 0000000..dc8a489 --- /dev/null +++ b/administrator/components/com_media/views/media/tmpl/default_folders.php @@ -0,0 +1,30 @@ +folders['data']->relative); + +?> + diff --git a/administrator/components/com_media/views/media/tmpl/default_navigation.php b/administrator/components/com_media/views/media/tmpl/default_navigation.php new file mode 100644 index 0000000..e83b0aa --- /dev/null +++ b/administrator/components/com_media/views/media/tmpl/default_navigation.php @@ -0,0 +1,19 @@ +getUserStateFromRequest('media.list.layout', 'layout', 'thumbs', 'word'); +?> + diff --git a/administrator/components/com_media/views/media/tmpl/index.html b/administrator/components/com_media/views/media/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/views/media/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/views/media/view.html.php b/administrator/components/com_media/views/media/view.html.php new file mode 100644 index 0000000..f9d85e1 --- /dev/null +++ b/administrator/components/com_media/views/media/view.html.php @@ -0,0 +1,159 @@ +getUserStateFromRequest('media.list.layout', 'layout', 'thumbs', 'word'); + + $document = JFactory::getDocument(); + + JHtml::_('behavior.framework', true); + + JHtml::_('script', 'media/mediamanager.js', true, true); + /* + JHtml::_('stylesheet', 'media/mediamanager.css', array(), true); + if ($lang->isRTL()) : + JHtml::_('stylesheet', 'media/mediamanager_rtl.css', array(), true); + endif; + */ + JHtml::_('behavior.modal'); + $document->addScriptDeclaration(" + window.addEvent('domready', function() + { + document.preview = SqueezeBox; + });"); + + // JHtml::_('script', 'system/mootree.js', true, true, false, false); + JHtml::_('stylesheet', 'system/mootree.css', array(), true); + if ($lang->isRTL()) : + JHtml::_('stylesheet', 'media/mootree_rtl.css', array(), true); + endif; + + if (DIRECTORY_SEPARATOR == '\\') + { + $base = str_replace(DIRECTORY_SEPARATOR, "\\\\", COM_MEDIA_BASE); + } + else + { + $base = COM_MEDIA_BASE; + } + + $js = " + var basepath = '".$base."'; + var viewstyle = '".$style."'; + "; + $document->addScriptDeclaration($js); + + /* + * Display form for FTP credentials? + * Don't set them here, as there are other functions called before this one if there is any file write operation + */ + $ftp = !JClientHelper::hasCredentials('ftp'); + + $session = JFactory::getSession(); + $state = $this->get('state'); + $this->session = $session; + $this->config = &$config; + $this->state = &$state; + $this->require_ftp = $ftp; + $this->folders_id = ' id="media-tree"'; + $this->folders = $this->get('folderTree'); + + // Set the toolbar + $this->addToolbar(); + + parent::display($tpl); + echo JHtml::_('behavior.keepalive'); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + // Get the toolbar object instance + $bar = JToolBar::getInstance('toolbar'); + $user = JFactory::getUser(); + + // Set the titlebar text + JToolbarHelper::title(JText::_('COM_MEDIA'), 'mediamanager.png'); + + // Add a upload button + if ($user->authorise('core.create', 'com_media')) + { + $title = JText::_('JTOOLBAR_UPLOAD'); + $dhtml = ""; + $bar->appendButton('Custom', $dhtml, 'upload'); + JToolbarHelper::divider(); + } + + // Add a create folder button + if ($user->authorise('core.create', 'com_media')) + { + $title = JText::_('COM_MEDIA_CREATE_NEW_FOLDER'); + $dhtml = ""; + $bar->appendButton('Custom', $dhtml, 'folder'); + JToolbarHelper::divider(); + } + + // Add a delete button + if ($user->authorise('core.delete', 'com_media')) + { + $title = JText::_('JTOOLBAR_DELETE'); + $dhtml = ""; + $bar->appendButton('Custom', $dhtml, 'delete'); + JToolbarHelper::divider(); + } + // Add a delete button + if ($user->authorise('core.admin', 'com_media')) + { + JToolbarHelper::preferences('com_media'); + JToolbarHelper::divider(); + } + JToolbarHelper::help('JHELP_CONTENT_MEDIA_MANAGER'); + } + + function getFolderLevel($folder) + { + $this->folders_id = null; + $txt = null; + if (isset($folder['children']) && count($folder['children'])) + { + $tmp = $this->folders; + $this->folders = $folder; + $txt = $this->loadTemplate('folders'); + $this->folders = $tmp; + } + return $txt; + } +} diff --git a/administrator/components/com_media/views/medialist/index.html b/administrator/components/com_media/views/medialist/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/views/medialist/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/views/medialist/tmpl/default.php b/administrator/components/com_media/views/medialist/tmpl/default.php new file mode 100644 index 0000000..caf6c58 --- /dev/null +++ b/administrator/components/com_media/views/medialist/tmpl/default.php @@ -0,0 +1,10 @@ + +
    +
    + + + + + + + + authorise('core.delete', 'com_media')):?> + + + + + + loadTemplate('up'); ?> + + folders); $i < $n; $i++) : + $this->setFolder($i); + echo $this->loadTemplate('folder'); + endfor; ?> + + documents); $i < $n; $i++) : + $this->setDoc($i); + echo $this->loadTemplate('doc'); + endfor; ?> + + images); $i < $n; $i++) : + $this->setImage($i); + echo $this->loadTemplate('img'); + endfor; ?> + + +
    + + + + +
    +
    diff --git a/administrator/components/com_media/views/medialist/tmpl/details_doc.php b/administrator/components/com_media/views/medialist/tmpl/details_doc.php new file mode 100644 index 0000000..ca25af6 --- /dev/null +++ b/administrator/components/com_media/views/medialist/tmpl/details_doc.php @@ -0,0 +1,41 @@ +trigger('onContentBeforeDisplay', array('com_media.file', &$this->_tmp_doc, &$params)); +?> + + + + _tmp_doc->icon_16, $this->_tmp_doc->title, null, true, true) ? JHtml::_('image', $this->_tmp_doc->icon_16, $this->_tmp_doc->title, array('width' => 16, 'height' => 16), true) : JHtml::_('image', 'media/con_info.png', $this->_tmp_doc->title, array('width' => 16, 'height' => 16), true);?> + + + _tmp_doc->title; ?> + +   + + + + _tmp_doc->size); ?> + + authorise('core.delete', 'com_media')):?> + + + + + + +trigger('onContentAfterDisplay', array('com_media.file', &$this->_tmp_doc, &$params)); +?> diff --git a/administrator/components/com_media/views/medialist/tmpl/details_folder.php b/administrator/components/com_media/views/medialist/tmpl/details_folder.php new file mode 100644 index 0000000..6265241 --- /dev/null +++ b/administrator/components/com_media/views/medialist/tmpl/details_folder.php @@ -0,0 +1,35 @@ + + + + + + + + _tmp_folder->name; ?> + +   + + +   + + + authorise('core.delete', 'com_media')):?> + + + + + + diff --git a/administrator/components/com_media/views/medialist/tmpl/details_img.php b/administrator/components/com_media/views/medialist/tmpl/details_img.php new file mode 100644 index 0000000..2a09aa3 --- /dev/null +++ b/administrator/components/com_media/views/medialist/tmpl/details_img.php @@ -0,0 +1,41 @@ +trigger('onContentBeforeDisplay', array('com_media.file', &$this->_tmp_img, &$params)); +?> + + + _tmp_img->path_relative, JText::sprintf('COM_MEDIA_IMAGE_TITLE', $this->_tmp_img->title, JHtml::_('number.bytes', $this->_tmp_img->size)), array('width' => $this->_tmp_img->width_16, 'height' => $this->_tmp_img->height_16)); ?> + + + escape($this->_tmp_img->title); ?> + + + _tmp_img->width, $this->_tmp_img->height); ?> + + + _tmp_img->size); ?> + + authorise('core.delete', 'com_media')):?> + + + + + + +trigger('onContentAfterDisplay', array('com_media.file', &$this->_tmp_img, &$params)); +?> diff --git a/administrator/components/com_media/views/medialist/tmpl/details_up.php b/administrator/components/com_media/views/medialist/tmpl/details_up.php new file mode 100644 index 0000000..4f4ebda --- /dev/null +++ b/administrator/components/com_media/views/medialist/tmpl/details_up.php @@ -0,0 +1,27 @@ + + + + + + + + .. + +   +   + authorise('core.delete', 'com_media')):?> +   + + diff --git a/administrator/components/com_media/views/medialist/tmpl/index.html b/administrator/components/com_media/views/medialist/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_media/views/medialist/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_media/views/medialist/tmpl/thumbs.php b/administrator/components/com_media/views/medialist/tmpl/thumbs.php new file mode 100644 index 0000000..09913c0 --- /dev/null +++ b/administrator/components/com_media/views/medialist/tmpl/thumbs.php @@ -0,0 +1,38 @@ + +
    +
      + loadTemplate('up'); + ?> + + folders); $i < $n; $i++) : + $this->setFolder($i); + echo $this->loadTemplate('folder'); + endfor; ?> + + documents); $i < $n; $i++) : + $this->setDoc($i); + echo $this->loadTemplate('doc'); + endfor; ?> + + images); $i < $n; $i++) : + $this->setImage($i); + echo $this->loadTemplate('img'); + endfor; ?> + + + + + +
    +
    diff --git a/administrator/components/com_media/views/medialist/tmpl/thumbs_doc.php b/administrator/components/com_media/views/medialist/tmpl/thumbs_doc.php new file mode 100644 index 0000000..90a2eb4 --- /dev/null +++ b/administrator/components/com_media/views/medialist/tmpl/thumbs_doc.php @@ -0,0 +1,33 @@ +trigger('onContentBeforeDisplay', array('com_media.file', &$this->_tmp_doc, &$params)); +?> +
  • + authorise('core.delete', 'com_media')):?> + x + +
    + + +
    + _tmp_doc->name, 10, false); ?> +
    +
  • +trigger('onContentAfterDisplay', array('com_media.file', &$this->_tmp_doc, &$params)); +?> diff --git a/administrator/components/com_media/views/medialist/tmpl/thumbs_folder.php b/administrator/components/com_media/views/medialist/tmpl/thumbs_folder.php new file mode 100644 index 0000000..8fe2aa0 --- /dev/null +++ b/administrator/components/com_media/views/medialist/tmpl/thumbs_folder.php @@ -0,0 +1,27 @@ + +
  • + authorise('core.delete', 'com_media')):?> + x + +
    + +
    + + + +
    + +
  • diff --git a/administrator/components/com_media/views/medialist/tmpl/thumbs_img.php b/administrator/components/com_media/views/medialist/tmpl/thumbs_img.php new file mode 100644 index 0000000..2580815 --- /dev/null +++ b/administrator/components/com_media/views/medialist/tmpl/thumbs_img.php @@ -0,0 +1,33 @@ +trigger('onContentBeforeDisplay', array('com_media.file', &$this->_tmp_img, &$params)); +?> +
  • + authorise('core.delete', 'com_media')):?> + x + +
    + + + +
  • +trigger('onContentAfterDisplay', array('com_media.file', &$this->_tmp_img, &$params)); +?> diff --git a/administrator/components/com_media/views/medialist/tmpl/thumbs_up.php b/administrator/components/com_media/views/medialist/tmpl/thumbs_up.php new file mode 100644 index 0000000..2e204c6 --- /dev/null +++ b/administrator/components/com_media/views/medialist/tmpl/thumbs_up.php @@ -0,0 +1,25 @@ + +
  • +
    +
    + + +
    +
    +
    +   +
    +
    + .. +
    +
  • diff --git a/administrator/components/com_media/views/medialist/view.html.php b/administrator/components/com_media/views/medialist/view.html.php new file mode 100644 index 0000000..c2aab75 --- /dev/null +++ b/administrator/components/com_media/views/medialist/view.html.php @@ -0,0 +1,91 @@ +addScriptDeclaration(" + window.addEvent('domready', function() + { + window.parent.document.updateUploader(); + $$('a.img-preview').each(function(el) + { + el.addEvent('click', function(e) + { + window.top.document.preview.fromElement(el); + return false; + }); + }); + });"); + + $images = $this->get('images'); + $documents = $this->get('documents'); + $folders = $this->get('folders'); + $state = $this->get('state'); + + $this->baseURL = JUri::root(); + $this->images = &$images; + $this->documents = &$documents; + $this->folders = &$folders; + $this->state = &$state; + + parent::display($tpl); + } + + function setFolder($index = 0) + { + if (isset($this->folders[$index])) + { + $this->_tmp_folder = &$this->folders[$index]; + } + else + { + $this->_tmp_folder = new JObject; + } + } + + function setImage($index = 0) + { + if (isset($this->images[$index])) + { + $this->_tmp_img = &$this->images[$index]; + } + else + { + $this->_tmp_img = new JObject; + } + } + + function setDoc($index = 0) + { + if (isset($this->documents[$index])) + { + $this->_tmp_doc = &$this->documents[$index]; + } + else + { + $this->_tmp_doc = new JObject; + } + } +} diff --git a/administrator/components/com_menus/access.xml b/administrator/components/com_menus/access.xml new file mode 100644 index 0000000..64347dc --- /dev/null +++ b/administrator/components/com_menus/access.xml @@ -0,0 +1,11 @@ + + +
    + + + + + + +
    +
    diff --git a/administrator/components/com_menus/config.xml b/administrator/components/com_menus/config.xml new file mode 100644 index 0000000..31dce2f --- /dev/null +++ b/administrator/components/com_menus/config.xml @@ -0,0 +1,55 @@ + + +
    + + + + + + + + +
    + +
    + + +
    +
    diff --git a/administrator/components/com_menus/controller.php b/administrator/components/com_menus/controller.php new file mode 100644 index 0000000..04e53ce --- /dev/null +++ b/administrator/components/com_menus/controller.php @@ -0,0 +1,62 @@ +input->get('view', 'menus'); + $layout = $this->input->get('layout', 'default'); + $id = $this->input->getInt('id'); + + // Check for edit form. + if ($view == 'menu' && $layout == 'edit' && !$this->checkEditId('com_menus.edit.menu', $id)) { + + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_menus&view=menus', false)); + + return false; + } + elseif ($view == 'item' && $layout == 'edit' && !$this->checkEditId('com_menus.edit.item', $id)) { + + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_menus&view=items', false)); + + return false; + } + + parent::display(); + + return $this; + } +} diff --git a/administrator/components/com_menus/controllers/index.html b/administrator/components/com_menus/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/controllers/item.php b/administrator/components/com_menus/controllers/item.php new file mode 100644 index 0000000..e78ee38 --- /dev/null +++ b/administrator/components/com_menus/controllers/item.php @@ -0,0 +1,345 @@ +setUserState($context . '.type', null); + $app->setUserState($context . '.link', null); + + $menuType = $app->getUserStateFromRequest($this->context . '.filter.menutype', 'menutype', 'mainmenu', 'cmd'); + + $this->setRedirect(JRoute::_('index.php?option=com_menus&view=item&menutype=' . $menuType . $this->getRedirectToItemAppend(), false)); + } + + return $result; + } + + /** + * Method to run batch operations. + * + * @param object $model The model. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 1.6 + */ + public function batch($model = null) + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $model = $this->getModel('Item', '', array()); + + // Preset the redirect + $this->setRedirect(JRoute::_('index.php?option=com_menus&view=items' . $this->getRedirectToListAppend(), false)); + + return parent::batch($model); + } + + /** + * Method to cancel an edit. + * + * @param string $key The name of the primary key of the URL variable. + * + * @return boolean True if access level checks pass, false otherwise. + * + * @since 1.6 + */ + public function cancel($key = null) + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $app = JFactory::getApplication(); + $context = 'com_menus.edit.item'; + $result = parent::cancel(); + + if ($result) + { + // Clear the ancillary data from the session. + $app->setUserState($context . '.type', null); + $app->setUserState($context . '.link', null); + } + } + + /** + * Method to edit an existing record. + * + * @param string $key The name of the primary key of the URL variable. + * @param string $urlVar The name of the URL variable if different from the primary key + * (sometimes required to avoid router collisions). + * + * @return boolean True if access level check and checkout passes, false otherwise. + * + * @since 1.6 + */ + public function edit($key = null, $urlVar = null) + { + $app = JFactory::getApplication(); + $result = parent::edit(); + + if ($result) + { + // Push the new ancillary data into the session. + $app->setUserState('com_menus.edit.item.type', null); + $app->setUserState('com_menus.edit.item.link', null); + } + + return true; + } + + /** + * Method to save a record. + * + * @param string $key The name of the primary key of the URL variable. + * @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions). + * + * @return boolean True if successful, false otherwise. + * + * @since 1.6 + */ + public function save($key = null, $urlVar = null) + { + // Check for request forgeries. + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $app = JFactory::getApplication(); + $model = $this->getModel('Item', '', array()); + $data = $this->input->post->get('jform', array(), 'array'); + $task = $this->getTask(); + $context = 'com_menus.edit.item'; + $recordId = $this->input->getInt('id'); + + if (!$this->checkEditId($context, $recordId)) + { + // Somehow the person just went to the form and saved it - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $recordId)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_menus&view=items' . $this->getRedirectToListAppend(), false)); + + return false; + } + + // Populate the row id from the session. + $data['id'] = $recordId; + + // The save2copy task needs to be handled slightly differently. + if ($task == 'save2copy') + { + // Check-in the original row. + if ($model->checkin($data['id']) === false) + { + // Check-in failed, go back to the item and display a notice. + $this->setMessage(JText::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError()), 'warning'); + return false; + } + + // Reset the ID and then treat the request as for Apply. + $data['id'] = 0; + $data['associations'] = array(); + $task = 'apply'; + } + + // Validate the posted data. + // This post is made up of two forms, one for the item and one for params. + $form = $model->getForm($data); + if (!$form) + { + JError::raiseError(500, $model->getError()); + + return false; + } + $data = $model->validate($form, $data); + + // Check for the special 'request' entry. + if ($data['type'] == 'component' && isset($data['request']) && is_array($data['request']) && !empty($data['request'])) + { + // Parse the submitted link arguments. + $args = array(); + parse_str(parse_url($data['link'], PHP_URL_QUERY), $args); + + // Merge in the user supplied request arguments. + $args = array_merge($args, $data['request']); + $data['link'] = 'index.php?' . urldecode(http_build_query($args, '', '&')); + unset($data['request']); + } + + // Check for validation errors. + if ($data === false) + { + // Get the validation messages. + $errors = $model->getErrors(); + + // Push up to three validation messages out to the user. + for ($i = 0, $n = count($errors); $i < $n && $i < 3; $i++) + { + if ($errors[$i] instanceof Exception) + { + $app->enqueueMessage($errors[$i]->getMessage(), 'warning'); + } + else + { + $app->enqueueMessage($errors[$i], 'warning'); + } + } + + // Save the data in the session. + $app->setUserState('com_menus.edit.item.data', $data); + + // Redirect back to the edit screen. + $this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId), false)); + + return false; + } + + // Attempt to save the data. + if (!$model->save($data)) + { + // Save the data in the session. + $app->setUserState('com_menus.edit.item.data', $data); + + // Redirect back to the edit screen. + $this->setMessage(JText::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()), 'warning'); + $this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId), false)); + + return false; + } + + // Save succeeded, check-in the row. + if ($model->checkin($data['id']) === false) + { + // Check-in failed, go back to the row and display a notice. + $this->setMessage(JText::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError()), 'warning'); + $this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId), false)); + + return false; + } + + $this->setMessage(JText::_('COM_MENUS_SAVE_SUCCESS')); + + // Redirect the user and adjust session state based on the chosen task. + switch ($task) + { + case 'apply': + // Set the row data in the session. + $recordId = $model->getState($this->context . '.id'); + $this->holdEditId($context, $recordId); + $app->setUserState('com_menus.edit.item.data', null); + $app->setUserState('com_menus.edit.item.type', null); + $app->setUserState('com_menus.edit.item.link', null); + + // Redirect back to the edit screen. + $this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId), false)); + break; + + case 'save2new': + // Clear the row id and data in the session. + $this->releaseEditId($context, $recordId); + $app->setUserState('com_menus.edit.item.data', null); + $app->setUserState('com_menus.edit.item.type', null); + $app->setUserState('com_menus.edit.item.link', null); + $app->setUserState('com_menus.edit.item.menutype', $model->getState('item.menutype')); + + // Redirect back to the edit screen. + $this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend(), false)); + break; + + default: + // Clear the row id and data in the session. + $this->releaseEditId($context, $recordId); + $app->setUserState('com_menus.edit.item.data', null); + $app->setUserState('com_menus.edit.item.type', null); + $app->setUserState('com_menus.edit.item.link', null); + + // Redirect to the list screen. + $this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_list . $this->getRedirectToListAppend(), false)); + break; + } + } + + /** + * Sets the type of the menu item currently being edited. + * + * @return void + * + * @since 1.6 + */ + public function setType() + { + $app = JFactory::getApplication(); + + // Get the posted values from the request. + $data = $this->input->post->get('jform', array(), 'array'); + + // Get the type. + $type = $data['type']; + + $type = json_decode(base64_decode($type)); + $title = isset($type->title) ? $type->title : null; + $recordId = isset($type->id) ? $type->id : 0; + + $specialTypes = array('alias', 'separator', 'url', 'heading'); + if (!in_array($title, $specialTypes)) + { + $title = 'component'; + } + + $app->setUserState('com_menus.edit.item.type', $title); + if ($title == 'component') + { + if (isset($type->request)) + { + $component = JComponentHelper::getComponent($type->request->option); + $data['component_id'] = $component->id; + + $app->setUserState('com_menus.edit.item.link', 'index.php?' . JUri::buildQuery((array) $type->request)); + } + } + // If the type is alias you just need the item id from the menu item referenced. + elseif ($title == 'alias') + { + $app->setUserState('com_menus.edit.item.link', 'index.php?Itemid='); + } + + unset($data['request']); + $data['type'] = $title; + if ($this->input->get('fieldtype') == 'type') + { + $data['link'] = $app->getUserState('com_menus.edit.item.link'); + } + + //Save the data in the session. + $app->setUserState('com_menus.edit.item.data', $data); + + $this->type = $type; + $this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId), false)); + } +} diff --git a/administrator/components/com_menus/controllers/items.php b/administrator/components/com_menus/controllers/items.php new file mode 100644 index 0000000..34cf74f --- /dev/null +++ b/administrator/components/com_menus/controllers/items.php @@ -0,0 +1,131 @@ +registerTask('unsetDefault', 'setDefault'); + } + + /** + * Proxy for getModel + * @since 1.6 + */ + public function getModel($name = 'Item', $prefix = 'MenusModel', $config = array()) + { + return parent::getModel($name, $prefix, array('ignore_request' => true)); + } + + /** + * Rebuild the nested set tree. + * + * @return bool False on failure or error, true on success. + * @since 1.6 + */ + public function rebuild() + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $this->setRedirect('index.php?option=com_menus&view=items'); + + $model = $this->getModel(); + + if ($model->rebuild()) + { + // Reorder succeeded. + $this->setMessage(JText::_('COM_MENUS_ITEMS_REBUILD_SUCCESS')); + return true; + } + else + { + // Rebuild failed. + $this->setMessage(JText::sprintf('COM_MENUS_ITEMS_REBUILD_FAILED')); + return false; + } + } + + public function saveorder() + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Get the arrays from the Request + $order = $this->input->post->get('order', null, 'array'); + $originalOrder = explode(',', $this->input->getString('original_order_values')); + + // Make sure something has changed + if (!($order === $originalOrder)) + { + parent::saveorder(); + } + else + { + // Nothing to reorder + $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list, false)); + return true; + } + } + + /** + * Method to set the home property for a list of items + * + * @since 1.6 + */ + public function setDefault() + { + // Check for request forgeries + JSession::checkToken('request') or die(JText::_('JINVALID_TOKEN')); + + // Get items to publish from the request. + $cid = $this->input->get('cid', array(), 'array'); + $data = array('setDefault' => 1, 'unsetDefault' => 0); + $task = $this->getTask(); + $value = JArrayHelper::getValue($data, $task, 0, 'int'); + + if (empty($cid)) + { + JError::raiseWarning(500, JText::_($this->text_prefix.'_NO_ITEM_SELECTED')); + } + else + { + // Get the model. + $model = $this->getModel(); + + // Make sure the item ids are integers + JArrayHelper::toInteger($cid); + + // Publish the items. + if (!$model->setHome($cid, $value)) + { + JError::raiseWarning(500, $model->getError()); + } else { + if ($value == 1) + { + $ntext = 'COM_MENUS_ITEMS_SET_HOME'; + } + else { + $ntext = 'COM_MENUS_ITEMS_UNSET_HOME'; + } + $this->setMessage(JText::plural($ntext, count($cid))); + } + } + + $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list, false)); + } +} diff --git a/administrator/components/com_menus/controllers/menu.php b/administrator/components/com_menus/controllers/menu.php new file mode 100644 index 0000000..f0849f8 --- /dev/null +++ b/administrator/components/com_menus/controllers/menu.php @@ -0,0 +1,158 @@ +setRedirect(JRoute::_('index.php?option=com_menus&view=menus', false)); + } + + /** + * Method to save a menu item. + * + * @return void + */ + public function save($key = null, $urlVar = null) + { + // Check for request forgeries. + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $app = JFactory::getApplication(); + $data = $this->input->post->get('jform', array(), 'array'); + $context = 'com_menus.edit.menu'; + $task = $this->getTask(); + $recordId = $this->input->getInt('id'); + + if (!$this->checkEditId($context, $recordId)) + { + // Somehow the person just went to the form and saved it - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $recordId)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list.$this->getRedirectToListAppend(), false)); + + return false; + } + + // Make sure we are not trying to modify an administrator menu. + if (isset($data['client_id']) && $data['client_id'] == 1){ + JError::raiseNotice(0, JText::_('COM_MENUS_MENU_TYPE_NOT_ALLOWED')); + + // Redirect back to the edit screen. + $this->setRedirect(JRoute::_('index.php?option=com_menus&view=menu&layout=edit', false)); + + return false; + } + + // Populate the row id from the session. + $data['id'] = $recordId; + + // Get the model and attempt to validate the posted data. + $model = $this->getModel('Menu'); + $form = $model->getForm(); + if (!$form) + { + JError::raiseError(500, $model->getError()); + + return false; + } + + $data = $model->validate($form, $data); + + // Check for validation errors. + if ($data === false) + { + // Get the validation messages. + $errors = $model->getErrors(); + + // Push up to three validation messages out to the user. + for ($i = 0, $n = count($errors); $i < $n && $i < 3; $i++) + { + if ($errors[$i] instanceof Exception) + { + $app->enqueueMessage($errors[$i]->getMessage(), 'warning'); + } + else { + $app->enqueueMessage($errors[$i], 'warning'); + } + } + // Save the data in the session. + $app->setUserState('com_menus.edit.menu.data', $data); + + // Redirect back to the edit screen. + $this->setRedirect(JRoute::_('index.php?option=com_menus&view=menu&layout=edit', false)); + + return false; + } + + // Attempt to save the data. + if (!$model->save($data)) + { + // Save the data in the session. + $app->setUserState('com_menus.edit.menu.data', $data); + + // Redirect back to the edit screen. + $this->setMessage(JText::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()), 'warning'); + $this->setRedirect(JRoute::_('index.php?option=com_menus&view=menu&layout=edit', false)); + + return false; + } + + $this->setMessage(JText::_('COM_MENUS_MENU_SAVE_SUCCESS')); + + // Redirect the user and adjust session state based on the chosen task. + switch ($task) + { + case 'apply': + // Set the record data in the session. + $recordId = $model->getState($this->context.'.id'); + $this->holdEditId($context, $recordId); + + // Redirect back to the edit screen. + $this->setRedirect(JRoute::_('index.php?option=com_menus&view=menu&layout=edit'.$this->getRedirectToItemAppend($recordId), false)); + break; + + case 'save2new': + // Clear the record id and data from the session. + $this->releaseEditId($context, $recordId); + $app->setUserState($context.'.data', null); + + // Redirect back to the edit screen. + $this->setRedirect(JRoute::_('index.php?option=com_menus&view=menu&layout=edit', false)); + break; + + default: + // Clear the record id and data from the session. + $this->releaseEditId($context, $recordId); + $app->setUserState($context.'.data', null); + + // Redirect to the list screen. + $this->setRedirect(JRoute::_('index.php?option=com_menus&view=menus', false)); + break; + } + } +} diff --git a/administrator/components/com_menus/controllers/menus.php b/administrator/components/com_menus/controllers/menus.php new file mode 100644 index 0000000..9d07134 --- /dev/null +++ b/administrator/components/com_menus/controllers/menus.php @@ -0,0 +1,202 @@ + true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } + + /** + * Removes an item + */ + public function delete() + { + // Check for request forgeries + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Get items to remove from the request. + $cid = $this->input->get('cid', array(), 'array'); + + if (!is_array($cid) || count($cid) < 1) + { + JError::raiseWarning(500, JText::_('COM_MENUS_NO_MENUS_SELECTED')); + } + else + { + // Get the model. + $model = $this->getModel(); + + // Make sure the item ids are integers + jimport('joomla.utilities.arrayhelper'); + JArrayHelper::toInteger($cid); + + // Remove the items. + if (!$model->delete($cid)) + { + $this->setMessage($model->getError()); + } + else + { + $this->setMessage(JText::plural('COM_MENUS_N_MENUS_DELETED', count($cid))); + } + } + + $this->setRedirect('index.php?option=com_menus&view=menus'); + } + + /** + * Rebuild the menu tree. + * + * @return bool False on failure or error, true on success. + */ + public function rebuild() + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $this->setRedirect('index.php?option=com_menus&view=menus'); + + $model = $this->getModel('Item'); + + if ($model->rebuild()) + { + // Reorder succeeded. + $this->setMessage(JText::_('JTOOLBAR_REBUILD_SUCCESS')); + return true; + } + else + { + // Rebuild failed. + $this->setMessage(JText::sprintf('JTOOLBAR_REBUILD_FAILED', $model->getMessage())); + return false; + } + } + + /** + * Temporary method. This should go into the 1.5 to 1.6 upgrade routines. + */ + public function resync() + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + $parts = null; + + try + { + $query->select('element, extension_id') + ->from('#__extensions') + ->where('type = ' . $db->quote('component')); + $db->setQuery($query); + + $components = $db->loadAssocList('element', 'extension_id'); + } + catch (RuntimeException $e) + { + return JError::raiseWarning(500, $e->getMessage()); + } + + // Load all the component menu links + $query->select($db->quoteName('id')) + ->select($db->quoteName('link')) + ->select($db->quoteName('component_id')) + ->from('#__menu') + ->where($db->quoteName('type') . ' = ' . $db->quote('component.item')); + $db->setQuery($query); + + try + { + $items = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + return JError::raiseWarning(500, $e->getMessage()); + } + + foreach ($items as $item) + { + // Parse the link. + parse_str(parse_url($item->link, PHP_URL_QUERY), $parts); + + // Tease out the option. + if (isset($parts['option'])) + { + $option = $parts['option']; + + // Lookup the component ID + if (isset($components[$option])) + { + $componentId = $components[$option]; + } + else + { + // Mismatch. Needs human intervention. + $componentId = -1; + } + + // Check for mis-matched component id's in the menu link. + if ($item->component_id != $componentId) + { + // Update the menu table. + $log = "Link $item->id refers to $item->component_id, converting to $componentId ($item->link)"; + echo "
    $log"; + + $query->clear(); + $query->update('#__menu') + ->set('component_id = ' . $componentId) + ->where('id = ' . $item->id); + + try + { + $db->setQuery($query)->execute(); + } + catch (RuntimeException $e) + { + return JError::raiseWarning(500, $e->getMessage()); + } + //echo "
    ".$db->getQuery(); + } + } + } + } +} diff --git a/administrator/components/com_menus/helpers/html/index.html b/administrator/components/com_menus/helpers/html/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/helpers/html/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/helpers/html/menus.php b/administrator/components/com_menus/helpers/html/menus.php new file mode 100644 index 0000000..bb0a06f --- /dev/null +++ b/administrator/components/com_menus/helpers/html/menus.php @@ -0,0 +1,209 @@ +getQuery(true) + ->select('m.id, m.title') + ->select('l.sef as lang_sef') + ->select('mt.title as menu_title') + ->from('#__menu as m') + ->join('LEFT', '#__menu_types as mt ON mt.menutype=m.menutype') + ->where('m.id IN (' . implode(',', array_values($associations)) . ')') + ->join('LEFT', '#__languages as l ON m.language=l.lang_code') + ->select('l.image') + ->select('l.title as language_title'); + $db->setQuery($query); + + try + { + $items = $db->loadObjectList('id'); + } + catch (runtimeException $e) + { + throw new Exception($e->getMessage(), 500); + } + + // Construct html + if ($items) + { + foreach ($items as &$item) + { + $text = strtoupper($item->lang_sef); + $url = JRoute::_('index.php?option=com_menus&task=item.edit&id=' . (int) $item->id); + $tooltipParts = array( + JHtml::_('image', 'mod_languages/' . $item->image . '.gif', + $item->language_title, + array('title' => $item->language_title), + true + ), + $item->title, + '(' . $item->menu_title . ')' + ); + $item->link = JHtml::_('tooltip', implode(' ', $tooltipParts), null, null, $text, $url, null, 'hasTooltip label label-association label-' . $item->lang_sef); + } + } + + $html = JLayoutHelper::render('joomla.content.associations', $items); + } + + return $html; + } + + /** + * Returns a published state on a grid + * + * @param integer $value The state value. + * @param integer $i The row index + * @param boolean $enabled An optional setting for access control on the action. + * @param string $checkbox An optional prefix for checkboxes. + * + * @return string The Html code + * + * @see JHtmlJGrid::state + * + * @since 1.7.1 + */ + public static function state($value, $i, $enabled = true, $checkbox = 'cb') + { + $states = array( + 9 => array( + 'unpublish', + '', + 'COM_MENUS_HTML_UNPUBLISH_HEADING', + '', + false, + 'publish', + 'publish' + ), + 8 => array( + 'publish', + '', + 'COM_MENUS_HTML_PUBLISH_HEADING', + '', + false, + 'unpublish', + 'unpublish' + ), + 7 => array( + 'unpublish', + '', + 'COM_MENUS_HTML_UNPUBLISH_SEPARATOR', + '', + false, + 'publish', + 'publish' + ), + 6 => array( + 'publish', + '', + 'COM_MENUS_HTML_PUBLISH_SEPARATOR', + '', + false, + 'unpublish', + 'unpublish' + ), + 5 => array( + 'unpublish', + '', + 'COM_MENUS_HTML_UNPUBLISH_ALIAS', + '', + false, + 'publish', + 'publish' + ), + 4 => array( + 'publish', + '', + 'COM_MENUS_HTML_PUBLISH_ALIAS', + '', + false, + 'unpublish', + 'unpublish' + ), + 3 => array( + 'unpublish', + '', + 'COM_MENUS_HTML_UNPUBLISH_URL', + '', + false, + 'publish', + 'publish' + ), + 2 => array( + 'publish', + '', + 'COM_MENUS_HTML_PUBLISH_URL', + '', + false, + 'unpublish', + 'unpublish' + ), + 1 => array( + 'unpublish', + 'COM_MENUS_EXTENSION_PUBLISHED_ENABLED', + 'COM_MENUS_HTML_UNPUBLISH_ENABLED', + 'COM_MENUS_EXTENSION_PUBLISHED_ENABLED', + true, + 'publish', + 'publish' + ), + 0 => array( + 'publish', + 'COM_MENUS_EXTENSION_UNPUBLISHED_ENABLED', + 'COM_MENUS_HTML_PUBLISH_ENABLED', + 'COM_MENUS_EXTENSION_UNPUBLISHED_ENABLED', + true, + 'unpublish', + 'unpublish' + ), + -1 => array( + 'unpublish', + 'COM_MENUS_EXTENSION_PUBLISHED_DISABLED', + 'COM_MENUS_HTML_UNPUBLISH_DISABLED', + 'COM_MENUS_EXTENSION_PUBLISHED_DISABLED', + true, + 'warning', + 'warning' + ), + -2 => array( + 'publish', + 'COM_MENUS_EXTENSION_UNPUBLISHED_DISABLED', + 'COM_MENUS_HTML_PUBLISH_DISABLED', + 'COM_MENUS_EXTENSION_UNPUBLISHED_DISABLED', + true, + 'unpublish', + 'unpublish' + ), + ); + + return JHtml::_('jgrid.state', $states, $value, $i, 'items.', $enabled, true, $checkbox); + } +} diff --git a/administrator/components/com_menus/helpers/index.html b/administrator/components/com_menus/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/helpers/menus.php b/administrator/components/com_menus/helpers/menus.php new file mode 100644 index 0000000..c837249 --- /dev/null +++ b/administrator/components/com_menus/helpers/menus.php @@ -0,0 +1,285 @@ +set($action->name, $user->authorise($action->name, $assetName)); + } + + return $result; + } + + /** + * Gets a standard form of a link for lookups. + * + * @param mixed A link string or array of request variables. + * + * @return mixed A link in standard option-view-layout form, or false if the supplied response is invalid. + */ + public static function getLinkKey($request) + { + if (empty($request)) + { + return false; + } + + // Check if the link is in the form of index.php?... + if (is_string($request)) + { + $args = array(); + if (strpos($request, 'index.php') === 0) + { + parse_str(parse_url(htmlspecialchars_decode($request), PHP_URL_QUERY), $args); + } + else + { + parse_str($request, $args); + } + $request = $args; + } + + // Only take the option, view and layout parts. + foreach ($request as $name => $value) + { + if ((!in_array($name, self::$_filter)) && (!($name == 'task' && !array_key_exists('view', $request)))) + { + // Remove the variables we want to ignore. + unset($request[$name]); + } + } + + ksort($request); + + return 'index.php?' . http_build_query($request, '', '&'); + } + + /** + * Get the menu list for create a menu module + * + * @return array The menu array list + * @since 1.6 + */ + public static function getMenuTypes() + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('a.menutype') + ->from('#__menu_types AS a'); + $db->setQuery($query); + + return $db->loadColumn(); + } + + /** + * Get a list of menu links for one or all menus. + * + * @param string An option menu to filter the list on, otherwise all menu links are returned as a grouped array. + * @param integer An optional parent ID to pivot results around. + * @param integer An optional mode. If parent ID is set and mode=2, the parent and children are excluded from the list. + * @param array An optional array of states + */ + public static function getMenuLinks($menuType = null, $parentId = 0, $mode = 0, $published = array(), $languages = array()) + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('a.id AS value, a.title AS text, a.alias, a.level, a.menutype, a.type, a.template_style_id, a.checked_out') + ->from('#__menu AS a') + ->join('LEFT', $db->quoteName('#__menu') . ' AS b ON a.lft > b.lft AND a.rgt < b.rgt'); + + // Filter by the type + if ($menuType) + { + $query->where('(a.menutype = ' . $db->quote($menuType) . ' OR a.parent_id = 0)'); + } + + if ($parentId) + { + if ($mode == 2) + { + // Prevent the parent and children from showing. + $query->join('LEFT', '#__menu AS p ON p.id = ' . (int) $parentId) + ->where('(a.lft <= p.lft OR a.rgt >= p.rgt)'); + } + } + + if (!empty($languages)) + { + if (is_array($languages)) + { + $languages = '(' . implode(',', array_map(array($db, 'quote'), $languages)) . ')'; + } + $query->where('a.language IN ' . $languages); + } + + if (!empty($published)) + { + if (is_array($published)) + { + $published = '(' . implode(',', $published) . ')'; + } + $query->where('a.published IN ' . $published); + } + + $query->where('a.published != -2') + ->group('a.id, a.title, a.level, a.menutype, a.type, a.template_style_id, a.checked_out, a.lft') + ->order('a.lft ASC'); + + // Get the options. + $db->setQuery($query); + + try + { + $links = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + return false; + } + + if (empty($menuType)) + { + // If the menutype is empty, group the items by menutype. + $query->clear() + ->select('*') + ->from('#__menu_types') + ->where('menutype <> ' . $db->quote('')) + ->order('title, menutype'); + $db->setQuery($query); + + try + { + $menuTypes = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + return false; + } + + // Create a reverse lookup and aggregate the links. + $rlu = array(); + foreach ($menuTypes as &$type) + { + $rlu[$type->menutype] = & $type; + $type->links = array(); + } + + // Loop through the list of menu links. + foreach ($links as &$link) + { + if (isset($rlu[$link->menutype])) + { + $rlu[$link->menutype]->links[] = & $link; + + // Cleanup garbage. + unset($link->menutype); + } + } + + return $menuTypes; + } + else + { + return $links; + } + } + + static public function getAssociations($pk) + { + $associations = array(); + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->from('#__menu as m') + ->join('INNER', '#__associations as a ON a.id=m.id AND a.context=' . $db->quote('com_menus.item')) + ->join('INNER', '#__associations as a2 ON a.key=a2.key') + ->join('INNER', '#__menu as m2 ON a2.id=m2.id') + ->where('m.id=' . (int) $pk) + ->select('m2.language, m2.id'); + $db->setQuery($query); + + try + { + $menuitems = $db->loadObjectList('language'); + } + catch (RuntimeException $e) + { + throw new Exception($e->getMessage(), 500); + } + + foreach ($menuitems as $tag => $item) + { + // Do not return itself as result + if ((int) $item->id != $pk) + { + $associations[$tag] = $item->id; + } + } + return $associations; + } +} diff --git a/administrator/components/com_menus/index.html b/administrator/components/com_menus/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/menus.php b/administrator/components/com_menus/menus.php new file mode 100644 index 0000000..48c763a --- /dev/null +++ b/administrator/components/com_menus/menus.php @@ -0,0 +1,19 @@ +authorise('core.manage', 'com_menus')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$controller = JControllerLegacy::getInstance('Menus'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_menus/menus.xml b/administrator/components/com_menus/menus.xml new file mode 100644 index 0000000..b17d182 --- /dev/null +++ b/administrator/components/com_menus/menus.xml @@ -0,0 +1,28 @@ + + + com_menus + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_MENUS_XML_DESCRIPTION + + + config.xml + controller.php + index.html + menus.php + controllers + helpers + models + views + + + language/en-GB.com_menus.ini + language/en-GB.com_menus.sys.ini + + + diff --git a/administrator/components/com_menus/models/fields/index.html b/administrator/components/com_menus/models/fields/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/models/fields/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/models/fields/menuordering.php b/administrator/components/com_menus/models/fields/menuordering.php new file mode 100644 index 0000000..b6ed9e1 --- /dev/null +++ b/administrator/components/com_menus/models/fields/menuordering.php @@ -0,0 +1,107 @@ +form->getValue('parent_id', 0); + if (empty($parent_id)) + { + return false; + } + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('a.id AS value, a.title AS text') + ->from('#__menu AS a') + + ->where('a.published >= 0') + ->where('a.parent_id =' . (int) $parent_id); + if ($menuType = $this->form->getValue('menutype')) + { + $query->where('a.menutype = ' . $db->quote($menuType)); + } + else + { + $query->where('a.menutype != ' . $db->quote('')); + } + + $query->order('a.lft ASC'); + + // Get the options. + $db->setQuery($query); + + try + { + $options = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + } + + $options = array_merge( + array(array('value' => '-1', 'text' => JText::_('COM_MENUS_ITEM_FIELD_ORDERING_VALUE_FIRST'))), + $options, + array(array('value' => '-2', 'text' => JText::_('COM_MENUS_ITEM_FIELD_ORDERING_VALUE_LAST'))) + ); + + // Merge any additional options in the XML definition. + $options = array_merge(parent::getOptions(), $options); + + return $options; + } + + /** + * Method to get the field input markup + * + * @return string The field input markup. + * @since 1.7 + */ + protected function getInput() + { + if ($this->form->getValue('id', 0) == 0) + { + return '' . JText::_('COM_MENUS_ITEM_FIELD_ORDERING_TEXT') . ''; + } + else + { + return parent::getInput(); + } + } +} diff --git a/administrator/components/com_menus/models/fields/menuparent.php b/administrator/components/com_menus/models/fields/menuparent.php new file mode 100644 index 0000000..0500030 --- /dev/null +++ b/administrator/components/com_menus/models/fields/menuparent.php @@ -0,0 +1,90 @@ +getQuery(true) + ->select('a.id AS value, a.title AS text, a.level') + ->from('#__menu AS a') + ->join('LEFT', $db->quoteName('#__menu') . ' AS b ON a.lft > b.lft AND a.rgt < b.rgt'); + + if ($menuType = $this->form->getValue('menutype')) + { + $query->where('a.menutype = ' . $db->quote($menuType)); + } + else + { + $query->where('a.menutype != ' . $db->quote('')); + } + + // Prevent parenting to children of this item. + if ($id = $this->form->getValue('id')) + { + $query->join('LEFT', $db->quoteName('#__menu') . ' AS p ON p.id = ' . (int) $id) + ->where('NOT(a.lft >= p.lft AND a.rgt <= p.rgt)'); + } + + $query->where('a.published != -2') + ->group('a.id, a.title, a.level, a.lft, a.rgt, a.menutype, a.parent_id, a.published') + ->order('a.lft ASC'); + + // Get the options. + $db->setQuery($query); + + try + { + $options = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + } + + // Pad the option text with spaces using depth level as a multiplier. + for ($i = 0, $n = count($options); $i < $n; $i++) + { + $options[$i]->text = str_repeat('- ', $options[$i]->level) . $options[$i]->text; + } + + // Merge any additional options in the XML definition. + $options = array_merge(parent::getOptions(), $options); + + return $options; + } +} diff --git a/administrator/components/com_menus/models/fields/menutype.php b/administrator/components/com_menus/models/fields/menutype.php new file mode 100644 index 0000000..a94ea03 --- /dev/null +++ b/administrator/components/com_menus/models/fields/menutype.php @@ -0,0 +1,81 @@ +form->getValue('id'); + $size = ($v = $this->element['size']) ? ' size="'.$v.'"' : ''; + $class = ($v = $this->element['class']) ? ' class="'.$v.'"' : 'class="text_area"'; + + // Get a reverse lookup of the base link URL to Title + $model = JModelLegacy::getInstance('menutypes', 'menusModel'); + $rlu = $model->getReverseLookup(); + + switch ($this->value) + { + case 'url': + $value = JText::_('COM_MENUS_TYPE_EXTERNAL_URL'); + break; + + case 'alias': + $value = JText::_('COM_MENUS_TYPE_ALIAS'); + break; + + case 'separator': + $value = JText::_('COM_MENUS_TYPE_SEPARATOR'); + break; + + case 'heading': + $value = JText::_('COM_MENUS_TYPE_HEADING'); + break; + + default: + $link = $this->form->getValue('link'); + // Clean the link back to the option, view and layout + $value = JText::_(JArrayHelper::getValue($rlu, MenusHelper::getLinkKey($link))); + break; + } + // Load the javascript and css + JHtml::_('behavior.framework'); + JHtml::_('behavior.modal'); + + $html[] = ' '.JText::_('JSELECT').''; + $html[] = ''; + + return implode("\n", $html); + } +} diff --git a/administrator/components/com_menus/models/forms/index.html b/administrator/components/com_menus/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/models/forms/item.xml b/administrator/components/com_menus/models/forms/item.xml new file mode 100644 index 0000000..521761e --- /dev/null +++ b/administrator/components/com_menus/models/forms/item.xml @@ -0,0 +1,218 @@ + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    diff --git a/administrator/components/com_menus/models/forms/item_alias.xml b/administrator/components/com_menus/models/forms/item_alias.xml new file mode 100644 index 0000000..814d1fd --- /dev/null +++ b/administrator/components/com_menus/models/forms/item_alias.xml @@ -0,0 +1,42 @@ + +
    + + + + +
    + +
    + +
    + + + + + + + + + + + + +
    +
    + + diff --git a/administrator/components/com_menus/models/forms/item_component.xml b/administrator/components/com_menus/models/forms/item_component.xml new file mode 100644 index 0000000..b3df663 --- /dev/null +++ b/administrator/components/com_menus/models/forms/item_component.xml @@ -0,0 +1,100 @@ + +
    + +
    + + + + + + + + + + + + +
    + +
    + + + + + + + + + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + +
    + +
    + +
    diff --git a/administrator/components/com_menus/models/forms/item_heading.xml b/administrator/components/com_menus/models/forms/item_heading.xml new file mode 100644 index 0000000..2fcb67e --- /dev/null +++ b/administrator/components/com_menus/models/forms/item_heading.xml @@ -0,0 +1,10 @@ + +
    + +
    +
    +
    + + diff --git a/administrator/components/com_menus/models/forms/item_separator.xml b/administrator/components/com_menus/models/forms/item_separator.xml new file mode 100644 index 0000000..3a41e0e --- /dev/null +++ b/administrator/components/com_menus/models/forms/item_separator.xml @@ -0,0 +1,24 @@ + +
    + +
    + + + + + + + + +
    +
    + + diff --git a/administrator/components/com_menus/models/forms/item_url.xml b/administrator/components/com_menus/models/forms/item_url.xml new file mode 100644 index 0000000..1892b07 --- /dev/null +++ b/administrator/components/com_menus/models/forms/item_url.xml @@ -0,0 +1,31 @@ + +
    + +
    + + + + + + + + + + + + +
    +
    + + diff --git a/administrator/components/com_menus/models/forms/menu.xml b/administrator/components/com_menus/models/forms/menu.xml new file mode 100644 index 0000000..6c587d7 --- /dev/null +++ b/administrator/components/com_menus/models/forms/menu.xml @@ -0,0 +1,45 @@ + +
    +
    + + + + + + + + +
    +
    diff --git a/administrator/components/com_menus/models/index.html b/administrator/components/com_menus/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/models/item.php b/administrator/components/com_menus/models/item.php new file mode 100644 index 0000000..d7c9c06 --- /dev/null +++ b/administrator/components/com_menus/models/item.php @@ -0,0 +1,1515 @@ +id)) + { + if ($record->published != -2) + { + return; + } + $user = JFactory::getUser(); + + return $user->authorise('core.delete', 'com_menus.item.' . (int) $record->id); + } + } + + /** + * Method to test whether a record can have its state edited. + * + * @param object A record object. + * + * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. + * @since 1.6 + */ + protected function canEditState($record) + { + $user = JFactory::getUser(); + + if (!empty($record->id)) + { + return $user->authorise('core.edit.state', 'com_menus.item.' . (int) $record->id); + } + // Default to component settings if menu item not known. + else + { + return parent::canEditState($record); + } + } + + /** + * Method to perform batch operations on an item or a set of items. + * + * @param array $commands An array of commands to perform. + * @param array $pks An array of item ids. + * @param array $contexts An array of item contexts. + * + * @return boolean Returns true on success, false on failure. + * + * @since 1.6 + */ + public function batch($commands, $pks, $contexts) + { + // Sanitize user ids. + $pks = array_unique($pks); + JArrayHelper::toInteger($pks); + + // Remove any values of zero. + if (array_search(0, $pks, true)) + { + unset($pks[array_search(0, $pks, true)]); + } + + if (empty($pks)) + { + $this->setError(JText::_('COM_MENUS_NO_ITEM_SELECTED')); + return false; + } + + $done = false; + + if (!empty($commands['menu_id'])) + { + $cmd = JArrayHelper::getValue($commands, 'move_copy', 'c'); + + if ($cmd == 'c') + { + $result = $this->batchCopy($commands['menu_id'], $pks, $contexts); + if (is_array($result)) + { + $pks = $result; + } + else + { + return false; + } + } + elseif ($cmd == 'm' && !$this->batchMove($commands['menu_id'], $pks, $contexts)) + { + return false; + } + $done = true; + } + + if (!empty($commands['assetgroup_id'])) + { + if (!$this->batchAccess($commands['assetgroup_id'], $pks, $contexts)) + { + return false; + } + + $done = true; + } + + if (!empty($commands['language_id'])) + { + if (!$this->batchLanguage($commands['language_id'], $pks, $contexts)) + { + return false; + } + + $done = true; + } + + if (!$done) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_INSUFFICIENT_BATCH_INFORMATION')); + return false; + } + + return true; + } + + /** + * Batch copy menu items to a new menu or parent. + * + * @param integer $value The new menu or sub-item. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return mixed An array of new IDs on success, boolean false on failure. + * + * @since 1.6 + */ + protected function batchCopy($value, $pks, $contexts) + { + // $value comes as {menutype}.{parent_id} + $parts = explode('.', $value); + $menuType = $parts[0]; + $parentId = (int) JArrayHelper::getValue($parts, 1, 0); + + $table = $this->getTable(); + $db = $this->getDbo(); + $query = $db->getQuery(true); + $i = 0; + + // Check that the parent exists + if ($parentId) + { + if (!$table->load($parentId)) + { + if ($error = $table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Non-fatal error + $this->setError(JText::_('JGLOBAL_BATCH_MOVE_PARENT_NOT_FOUND')); + $parentId = 0; + } + } + } + + // If the parent is 0, set it to the ID of the root item in the tree + if (empty($parentId)) + { + if (!$parentId = $table->getRootId()) + { + $this->setError($db->getErrorMsg()); + return false; + } + } + + // Check that user has create permission for menus + $user = JFactory::getUser(); + if (!$user->authorise('core.create', 'com_menus')) + { + $this->setError(JText::_('COM_MENUS_BATCH_MENU_ITEM_CANNOT_CREATE')); + return false; + } + + // We need to log the parent ID + $parents = array(); + + // Calculate the emergency stop count as a precaution against a runaway loop bug + $query->select('COUNT(id)') + ->from($db->quoteName('#__menu')); + $db->setQuery($query); + + try + { + $count = $db->loadResult(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + // Parent exists so we let's proceed + while (!empty($pks) && $count > 0) + { + // Pop the first id off the stack + $pk = array_shift($pks); + + $table->reset(); + + // Check that the row actually exists + if (!$table->load($pk)) + { + if ($error = $table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Not fatal error + $this->setError(JText::sprintf('JGLOBAL_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + } + + // Copy is a bit tricky, because we also need to copy the children + $query->clear() + ->select('id') + ->from($db->quoteName('#__menu')) + ->where('lft > ' . (int) $table->lft) + ->where('rgt < ' . (int) $table->rgt); + $db->setQuery($query); + $childIds = $db->loadColumn(); + + // Add child ID's to the array only if they aren't already there. + foreach ($childIds as $childId) + { + if (!in_array($childId, $pks)) + { + array_push($pks, $childId); + } + } + + // Make a copy of the old ID and Parent ID + $oldId = $table->id; + $oldParentId = $table->parent_id; + + // Reset the id because we are making a copy. + $table->id = 0; + + // If we a copying children, the Old ID will turn up in the parents list + // otherwise it's a new top level item + $table->parent_id = isset($parents[$oldParentId]) ? $parents[$oldParentId] : $parentId; + $table->menutype = $menuType; + + // Set the new location in the tree for the node. + $table->setLocation($table->parent_id, 'last-child'); + + // TODO: Deal with ordering? + //$table->ordering = 1; + $table->level = null; + $table->lft = null; + $table->rgt = null; + $table->home = 0; + + // Alter the title & alias + list($title, $alias) = $this->generateNewTitle($table->parent_id, $table->alias, $table->title); + $table->title = $title; + $table->alias = $alias; + + // Check the row. + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + // Store the row. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Get the new item ID + $newId = $table->get('id'); + + // Add the new ID to the array + $newIds[$i] = $newId; + $i++; + + // Now we log the old 'parent' to the new 'parent' + $parents[$oldId] = $table->id; + $count--; + } + + // Rebuild the hierarchy. + if (!$table->rebuild()) + { + $this->setError($table->getError()); + return false; + } + + // Rebuild the tree path. + if (!$table->rebuildPath($table->id)) + { + $this->setError($table->getError()); + return false; + } + + // Clean the cache + $this->cleanCache(); + + return $newIds; + } + + /** + * Batch move menu items to a new menu or parent. + * + * @param integer $value The new menu or sub-item. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return boolean True on success. + * + * @since 1.6 + */ + protected function batchMove($value, $pks, $contexts) + { + // $value comes as {menutype}.{parent_id} + $parts = explode('.', $value); + $menuType = $parts[0]; + $parentId = (int) JArrayHelper::getValue($parts, 1, 0); + + $table = $this->getTable(); + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Check that the parent exists. + if ($parentId) + { + if (!$table->load($parentId)) + { + if ($error = $table->getError()) + { + // Fatal error + $this->setError($error); + + return false; + } + else + { + // Non-fatal error + $this->setError(JText::_('JGLOBAL_BATCH_MOVE_PARENT_NOT_FOUND')); + $parentId = 0; + } + } + } + + // Check that user has create and edit permission for menus + $user = JFactory::getUser(); + if (!$user->authorise('core.create', 'com_menus')) + { + $this->setError(JText::_('COM_MENUS_BATCH_MENU_ITEM_CANNOT_CREATE')); + return false; + } + + if (!$user->authorise('core.edit', 'com_menus')) + { + $this->setError(JText::_('COM_MENUS_BATCH_MENU_ITEM_CANNOT_EDIT')); + return false; + } + + // We are going to store all the children and just moved the menutype + $children = array(); + + // Parent exists so we let's proceed + foreach ($pks as $pk) + { + // Check that the row actually exists + if (!$table->load($pk)) + { + if ($error = $table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Not fatal error + $this->setError(JText::sprintf('JGLOBAL_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + } + + // Set the new location in the tree for the node. + $table->setLocation($parentId, 'last-child'); + + // Set the new Parent Id + $table->parent_id = $parentId; + + // Check if we are moving to a different menu + if ($menuType != $table->menutype) + { + // Add the child node ids to the children array. + $query->clear() + ->select($db->quoteName('id')) + ->from($db->quoteName('#__menu')) + ->where($db->quoteName('lft') . ' BETWEEN ' . (int) $table->lft . ' AND ' . (int) $table->rgt); + $db->setQuery($query); + $children = array_merge($children, (array) $db->loadColumn()); + } + + // Check the row. + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // Store the row. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Rebuild the tree path. + if (!$table->rebuildPath()) + { + $this->setError($table->getError()); + return false; + } + } + + // Process the child rows + if (!empty($children)) + { + // Remove any duplicates and sanitize ids. + $children = array_unique($children); + JArrayHelper::toInteger($children); + + // Update the menutype field in all nodes where necessary. + $query->clear() + ->update($db->quoteName('#__menu')) + ->set($db->quoteName('menutype') . ' = ' . $db->quote($menuType)) + ->where($db->quoteName('id') . ' IN (' . implode(',', $children) . ')'); + $db->setQuery($query); + + try + { + $db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + } + + // Clean the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to check if you can save a record. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * @since 1.6 + */ + protected function canSave($data = array(), $key = 'id') + { + return JFactory::getUser()->authorise('core.edit', $this->option); + } + + /** + * Method to get the row form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * @return mixed A JForm object on success, false on failure + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + // The folder and element vars are passed when saving the form. + if (empty($data)) + { + $item = $this->getItem(); + $this->setState('item.link', $item->link); + // The type should already be set. + } + else + { + $this->setState('item.link', JArrayHelper::getValue($data, 'link')); + $this->setState('item.type', JArrayHelper::getValue($data, 'type')); + } + + // Get the form. + $form = $this->loadForm('com_menus.item', 'item', array('control' => 'jform', 'load_data' => $loadData), true); + if (empty($form)) + { + return false; + } + + // Modify the form based on access controls. + if (!$this->canEditState((object) $data)) + { + // Disable fields for display. + $form->setFieldAttribute('menuordering', 'disabled', 'true'); + $form->setFieldAttribute('published', 'disabled', 'true'); + + // Disable fields while saving. + // The controller has already verified this is an article you can edit. + $form->setFieldAttribute('menuordering', 'filter', 'unset'); + $form->setFieldAttribute('published', 'filter', 'unset'); + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = array_merge((array) $this->getItem(), (array) JFactory::getApplication()->getUserState('com_menus.edit.item.data', array())); + + $this->preprocessData('com_menus.item', $data); + + return $data; + } + + /** + * Get the necessary data to load an item help screen. + * + * @return object An object with key, url, and local properties for loading the item help screen. + * @since 1.6 + */ + public function getHelp() + { + return (object) array('key' => $this->helpKey, 'url' => $this->helpURL, 'local' => $this->helpLocal); + } + + /** + * Method to get a menu item. + * + * @param integer $pk An optional id of the object to get, otherwise the id from the model state is used. + * + * @return mixed Menu item data object on success, false on failure. + * @since 1.6 + */ + public function getItem($pk = null) + { + $pk = (!empty($pk)) ? $pk : (int) $this->getState('item.id'); + + // Get a level row instance. + $table = $this->getTable(); + + // Attempt to load the row. + $table->load($pk); + + // Check for a table object error. + if ($error = $table->getError()) + { + $this->setError($error); + return false; + } + + // Prime required properties. + + if ($type = $this->getState('item.type')) + { + $table->type = $type; + } + + if (empty($table->id)) + { + $table->parent_id = $this->getState('item.parent_id'); + $table->menutype = $this->getState('item.menutype'); + $table->params = '{}'; + } + + // If the link has been set in the state, possibly changing link type. + if ($link = $this->getState('item.link')) + { + // Check if we are changing away from the actual link type. + if (MenusHelper::getLinkKey($table->link) != MenusHelper::getLinkKey($link)) + { + $table->link = $link; + } + } + + switch ($table->type) + { + case 'alias': + $table->component_id = 0; + $args = array(); + + parse_str(parse_url($table->link, PHP_URL_QUERY), $args); + break; + + case 'separator': + case 'heading': + $table->link = ''; + $table->component_id = 0; + break; + + case 'url': + $table->component_id = 0; + + parse_str(parse_url($table->link, PHP_URL_QUERY)); + break; + + case 'component': + default: + // Enforce a valid type. + $table->type = 'component'; + + // Ensure the integrity of the component_id field is maintained, particularly when changing the menu item type. + $args = array(); + parse_str(parse_url($table->link, PHP_URL_QUERY), $args); + + if (isset($args['option'])) + { + // Load the language file for the component. + $lang = JFactory::getLanguage(); + $lang->load($args['option'], JPATH_ADMINISTRATOR, null, false, false) + || $lang->load($args['option'], JPATH_ADMINISTRATOR . '/components/' . $args['option'], null, false, false) + || $lang->load($args['option'], JPATH_ADMINISTRATOR, $lang->getDefault(), false, false) + || $lang->load($args['option'], JPATH_ADMINISTRATOR . '/components/' . $args['option'], $lang->getDefault(), false, false); + + // Determine the component id. + $component = JComponentHelper::getComponent($args['option']); + if (isset($component->id)) + { + $table->component_id = $component->id; + } + } + break; + } + + // We have a valid type, inject it into the state for forms to use. + $this->setState('item.type', $table->type); + + // Convert to the JObject before adding the params. + $properties = $table->getProperties(1); + $result = JArrayHelper::toObject($properties); + + // Convert the params field to an array. + $registry = new JRegistry; + $registry->loadString($table->params); + $result->params = $registry->toArray(); + + // Merge the request arguments in to the params for a component. + if ($table->type == 'component') + { + // Note that all request arguments become reserved parameter names. + $result->request = $args; + $result->params = array_merge($result->params, $args); + } + + if ($table->type == 'alias') + { + // Note that all request arguments become reserved parameter names. + $args = array(); + parse_str(parse_url($table->link, PHP_URL_QUERY), $args); + $result->params = array_merge($result->params, $args); + } + + if ($table->type == 'url') + { + // Note that all request arguments become reserved parameter names. + $args = array(); + parse_str(parse_url($table->link, PHP_URL_QUERY), $args); + $result->params = array_merge($result->params, $args); + } + + // Load associated menu items + $app = JFactory::getApplication(); + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + if ($assoc) + { + if ($pk != null) + { + $result->associations = MenusHelper::getAssociations($pk); + } + else + { + $result->associations = array(); + } + } + $result->menuordering = $pk; + + return $result; + } + + /** + * Get the list of modules not in trash. + * + * @return mixed An array of module records (id, title, position), or false on error. + * @since 1.6 + */ + public function getModules() + { + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Join on the module-to-menu mapping table. + // We are only interested if the module is displayed on ALL or THIS menu item (or the inverse ID number). + //sqlsrv changes for modulelink to menu manager + $query->select('a.id, a.title, a.position, a.published, map.menuid') + ->from('#__modules AS a') + ->join('LEFT', sprintf('#__modules_menu AS map ON map.moduleid = a.id AND map.menuid IN (0, %1$d, -%1$d)', $this->getState('item.id'))) + ->select('(SELECT COUNT(*) FROM #__modules_menu WHERE moduleid = a.id AND menuid < 0) AS ' . $db->quoteName('except')); + + // Join on the asset groups table. + $query->select('ag.title AS access_title') + ->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access') + ->where('a.published >= 0') + ->where('a.client_id = 0') + ->order('a.position, a.ordering'); + + $db->setQuery($query); + + try + { + $result = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + return $result; + } + + /** + * A protected method to get the where clause for the reorder + * This ensures that the row will be moved relative to a row with the same menutype + * + * @param JTableMenu $table instance + * + * @return array An array of conditions to add to add to ordering queries. + * @since 1.6 + */ + protected function getReorderConditions($table) + { + return 'menutype = ' . $this->_db->quote($table->menutype); + } + + /** + * Returns a Table object, always creating it + * + * @param type $type The table type to instantiate + * @param string $prefix A prefix for the table class name. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return JTable A database object + * @since 1.6 + */ + public function getTable($type = 'Menu', $prefix = 'MenusTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @return void + * @since 1.6 + */ + protected function populateState() + { + $app = JFactory::getApplication('administrator'); + + // Load the User state. + $pk = $app->input->getInt('id'); + $this->setState('item.id', $pk); + + if (!($parentId = $app->getUserState('com_menus.edit.item.parent_id'))) + { + $parentId = $app->input->getInt('parent_id'); + } + $this->setState('item.parent_id', $parentId); + + $menuType = $app->getUserState('com_menus.edit.item.menutype'); + if ($app->input->getString('menutype', false)) + { + $menuType = $app->input->getString('menutype', 'mainmenu'); + } + $this->setState('item.menutype', $menuType); + + if (!($type = $app->getUserState('com_menus.edit.item.type'))) + { + $type = $app->input->get('type'); + // Note a new menu item will have no field type. + // The field is required so the user has to change it. + } + $this->setState('item.type', $type); + + if ($link = $app->getUserState('com_menus.edit.item.link')) + { + $this->setState('item.link', $link); + } + + // Load the parameters. + $params = JComponentHelper::getParams('com_menus'); + $this->setState('params', $params); + } + + /** + * @param object $form A form object. + * @param mixed $data The data expected for the form. + * + * @return void + * @since 1.6 + * @throws Exception if there is an error in the form event. + */ + protected function preprocessForm(JForm $form, $data, $group = 'content') + { + $link = $this->getState('item.link'); + $type = $this->getState('item.type'); + $formFile = false; + + // Initialise form with component view params if available. + if ($type == 'component') + { + + $link = htmlspecialchars_decode($link); + + // Parse the link arguments. + $args = array(); + parse_str(parse_url(htmlspecialchars_decode($link), PHP_URL_QUERY), $args); + + // Confirm that the option is defined. + $option = ''; + $base = ''; + if (isset($args['option'])) + { + // The option determines the base path to work with. + $option = $args['option']; + $base = JPATH_SITE . '/components/' . $option; + } + + // Confirm a view is defined. + $formFile = false; + if (isset($args['view'])) + { + $view = $args['view']; + + // Determine the layout to search for. + if (isset($args['layout'])) + { + $layout = $args['layout']; + } + else + { + $layout = 'default'; + } + + $formFile = false; + + // Check for the layout XML file. Use standard xml file if it exists. + $path = JPath::clean($base . '/views/' . $view . '/tmpl/' . $layout . '.xml'); + if (is_file($path)) + { + $formFile = $path; + } + + // if custom layout, get the xml file from the template folder + // template folder is first part of file name -- template:folder + if (!$formFile && (strpos($layout, ':') > 0)) + { + $temp = explode(':', $layout); + $templatePath = JPATH::clean(JPATH_SITE . '/templates/' . $temp[0] . '/html/' . $option . '/' . $view . '/' . $temp[1] . '.xml'); + if (is_file($templatePath)) + { + $formFile = $templatePath; + } + } + } + + //Now check for a view manifest file + if (!$formFile) + { + if (isset($view) && is_file($path = JPath::clean($base . '/views/' . $view . '/metadata.xml'))) + { + $formFile = $path; + } + else + { + //Now check for a component manifest file + $path = JPath::clean($base . '/metadata.xml'); + if (is_file($path)) + { + $formFile = $path; + } + } + } + } + + if ($formFile) + { + // If an XML file was found in the component, load it first. + // We need to qualify the full path to avoid collisions with component file names. + + if ($form->loadFile($formFile, true, '/metadata') == false) + { + throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); + } + + // Attempt to load the xml file. + if (!$xml = simplexml_load_file($formFile)) + { + throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); + } + + // Get the help data from the XML file if present. + $help = $xml->xpath('/metadata/layout/help'); + } + else + { + // We don't have a component. Load the form XML to get the help path + $xmlFile = JPath::find(JPATH_ROOT . '/administrator/components/com_menus/models/forms', 'item_' . $type . '.xml'); + + // Attempt to load the xml file. + if ($xmlFile && !$xml = simplexml_load_file($xmlFile)) + { + throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); + } + + // Get the help data from the XML file if present. + $help = $xml->xpath('/form/help'); + } + + if (!empty($help)) + { + $helpKey = trim((string) $help[0]['key']); + $helpURL = trim((string) $help[0]['url']); + $helpLoc = trim((string) $help[0]['local']); + + $this->helpKey = $helpKey ? $helpKey : $this->helpKey; + $this->helpURL = $helpURL ? $helpURL : $this->helpURL; + $this->helpLocal = (($helpLoc == 'true') || ($helpLoc == '1') || ($helpLoc == 'local')) ? true : false; + } + + // Now load the component params. + // TODO: Work out why 'fixing' this breaks JForm + if ($isNew = false) + { + $path = JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $option . '/config.xml'); + } + else + { + $path = 'null'; + } + + if (is_file($path)) + { + // Add the component params last of all to the existing form. + if (!$form->load($path, true, '/config')) + { + throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); + } + } + + // Load the specific type file + if (!$form->loadFile('item_' . $type, false, false)) + { + throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); + } + + // Association menu items + $app = JFactory::getApplication(); + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $languages = JLanguageHelper::getLanguages('lang_code'); + + $addform = new SimpleXMLElement('
    '); + $fields = $addform->addChild('fields'); + $fields->addAttribute('name', 'associations'); + $fieldset = $fields->addChild('fieldset'); + $fieldset->addAttribute('name', 'item_associations'); + $fieldset->addAttribute('description', 'COM_MENUS_ITEM_ASSOCIATIONS_FIELDSET_DESC'); + $add = false; + foreach ($languages as $tag => $language) + { + if ($tag != $data['language']) + { + $add = true; + $field = $fieldset->addChild('field'); + $field->addAttribute('name', $tag); + $field->addAttribute('type', 'menuitem'); + $field->addAttribute('language', $tag); + $field->addAttribute('label', $language->title); + $field->addAttribute('translate_label', 'false'); + $option = $field->addChild('option', 'COM_MENUS_ITEM_FIELD_ASSOCIATION_NO_VALUE'); + $option->addAttribute('value', ''); + } + } + if ($add) + { + $form->load($addform, false); + } + } + + // Trigger the default form events. + parent::preprocessForm($form, $data, $group); + } + + /** + * Method rebuild the entire nested set tree. + * + * @return boolean False on failure or error, true otherwise. + * @since 1.6 + */ + public function rebuild() + { + // Initialiase variables. + $db = $this->getDbo(); + $query = $db->getQuery(true); + $table = $this->getTable(); + + if (!$table->rebuild()) + { + $this->setError($table->getError()); + return false; + } + + $query->select('id, params') + ->from('#__menu') + ->where('params NOT LIKE ' . $db->quote('{%')) + ->where('params <> ' . $db->quote('')); + $db->setQuery($query); + + try + { + $items = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + return JError::raiseWarning(500, $e->getMessage()); + } + + foreach ($items as &$item) + { + $registry = new JRegistry; + $registry->loadString($item->params); + $params = (string) $registry; + + $query->clear(); + $query->update('#__menu') + ->set('params = ' . $db->quote($params)) + ->where('id = ' . $item->id); + + try + { + $db->setQuery($query)->execute(); + } + catch (RuntimeException $e) + { + return JError::raiseWarning(500, $e->getMessage()); + } + + unset($registry); + } + + // Clean the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to save the form data. + * + * @param array $data The form data. + * + * @return boolean True on success. + * @since 1.6 + */ + public function save($data) + { + $pk = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('item.id'); + $isNew = true; + $table = $this->getTable(); + + // Load the row if saving an existing item. + if ($pk > 0) + { + $table->load($pk); + $isNew = false; + } + if (!$isNew && $table->menutype == $data['menutype']) + { + if ($table->parent_id == $data['parent_id']) + { + + // If first is chosen make the item the first child of the selected parent. + if ($data['menuordering'] == -1) + { + $table->setLocation($data['parent_id'], 'first-child'); + } + // If last is chosen make it the last child of the selected parent. + elseif ($data['menuordering'] == -2) + { + $table->setLocation($data['parent_id'], 'last-child'); + } + // Don't try to put an item after itself. All other ones put after the selected item. + // $data['id'] is empty means it's a save as copy + elseif ($data['menuordering'] && $table->id != $data['menuordering'] || empty($data['id'])) + { + $table->setLocation($data['menuordering'], 'after'); + } + // Just leave it where it is if no change is made. + elseif ($data['menuordering'] && $table->id == $data['menuordering']) + { + unset($data['menuordering']); + } + } + // Set the new parent id if parent id not matched and put in last position + else + { + $table->setLocation($data['parent_id'], 'last-child'); + } + } + // We have a new item, so it is not a change. + elseif ($isNew) + { + $table->setLocation($data['parent_id'], 'last-child'); + } + // The menu type has changed so we need to just put this at the bottom + // of the root level. + else + { + $table->setLocation(1, 'last-child'); + } + + // Bind the data. + if (!$table->bind($data)) + { + $this->setError($table->getError()); + return false; + } + + // Alter the title & alias for save as copy. Also, unset the home record. + if (!$isNew && $data['id'] == 0) + { + list($title, $alias) = $this->generateNewTitle($table->parent_id, $table->alias, $table->title); + $table->title = $title; + $table->alias = $alias; + $table->published = 0; + $table->home = 0; + } + + // Check the data. + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // Store the data. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Rebuild the tree path. + if (!$table->rebuildPath($table->id)) + { + $this->setError($table->getError()); + return false; + } + + $this->setState('item.id', $table->id); + $this->setState('item.menutype', $table->menutype); + + // Load associated menu items + $app = JFactory::getApplication(); + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + if ($assoc) + { + // Adding self to the association + $associations = $data['associations']; + foreach ($associations as $tag => $id) + { + if (empty($id)) + { + unset($associations[$tag]); + } + } + + // Detecting all item menus + $all_language = $table->language == '*'; + if ($all_language && !empty($associations)) + { + JError::raiseNotice(403, JText::_('COM_MENUS_ERROR_ALL_LANGUAGE_ASSOCIATED')); + } + + $associations[$table->language] = $table->id; + + // Deleting old association for these items + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->delete('#__associations') + ->where('context=' . $db->quote('com_menus.item')) + ->where('id IN (' . implode(',', $associations) . ')'); + $db->setQuery($query); + + try + { + $db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + if (!$all_language && count($associations) > 1) + { + // Adding new association for these items + $key = md5(json_encode($associations)); + $query->clear() + ->insert('#__associations'); + foreach ($associations as $id) + { + $query->values($id . ',' . $db->quote('com_menus.item') . ',' . $db->quote($key)); + } + $db->setQuery($query); + + try + { + $db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + } + } + + // Clean the cache + $this->cleanCache(); + + if (isset($data['link'])) + { + $base = JUri::base(); + $juri = JUri::getInstance($base . $data['link']); + $option = $juri->getVar('option'); + + // Clean the cache + parent::cleanCache($option); + } + + return true; + } + + /** + * Method to save the reordered nested set tree. + * First we save the new order values in the lft values of the changed ids. + * Then we invoke the table rebuild to implement the new ordering. + * + * @param array $idArray id's of rows to be reordered + * @param array $lft_array lft values of rows to be reordered + * + * @return boolean false on failuer or error, true otherwise + * @since 1.6 + */ + public function saveorder($idArray = null, $lft_array = null) + { + // Get an instance of the table object. + $table = $this->getTable(); + + if (!$table->saveorder($idArray, $lft_array)) + { + $this->setError($table->getError()); + return false; + } + + // Clean the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to change the home state of one or more items. + * + * @param array $pks A list of the primary keys to change. + * @param integer $value The value of the home state. + * + * @return boolean True on success. + * @since 1.6 + */ + public function setHome(&$pks, $value = 1) + { + $table = $this->getTable(); + $pks = (array) $pks; + + $languages = array(); + $onehome = false; + + // Remember that we can set a home page for different languages, + // so we need to loop through the primary key array. + foreach ($pks as $i => $pk) + { + if ($table->load($pk)) + { + if (!array_key_exists($table->language, $languages)) + { + $languages[$table->language] = true; + + if ($table->home == $value) + { + unset($pks[$i]); + JError::raiseNotice(403, JText::_('COM_MENUS_ERROR_ALREADY_HOME')); + } + else + { + $table->home = $value; + if ($table->language == '*') + { + $table->published = 1; + } + + if (!$this->canSave($table)) + { + // Prune items that you can't change. + unset($pks[$i]); + JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED')); + } + elseif (!$table->check()) + { + // Prune the items that failed pre-save checks. + unset($pks[$i]); + JError::raiseWarning(403, $table->getError()); + } + elseif (!$table->store()) + { + // Prune the items that could not be stored. + unset($pks[$i]); + JError::raiseWarning(403, $table->getError()); + } + } + } + else + { + unset($pks[$i]); + if (!$onehome) + { + $onehome = true; + JError::raiseNotice(403, JText::sprintf('COM_MENUS_ERROR_ONE_HOME')); + } + } + } + } + + // Clean the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to change the published state of one or more records. + * + * @param array &$pks A list of the primary keys to change. + * @param integer $value The value of the published state. + * + * @return boolean True on success. + * + * @since 1.6 + */ + public function publish(&$pks, $value = 1) + { + $table = $this->getTable(); + $pks = (array) $pks; + + // Default menu item existence checks. + if ($value != 1) + { + foreach ($pks as $i => $pk) + { + if ($table->load($pk) && $table->home && $table->language == '*') + { + // Prune items that you can't change. + JError::raiseWarning(403, JText::_('JLIB_DATABASE_ERROR_MENU_UNPUBLISH_DEFAULT_HOME')); + unset($pks[$i]); + break; + } + } + } + + // Clean the cache + $this->cleanCache(); + + // Ensure that previous checks doesn't empty the array + if (empty($pks)) + { + return true; + } + + return parent::publish($pks, $value); + } + + /** + * Method to change the title & alias. + * + * @param integer $parent_id The id of the parent. + * @param string $alias The alias. + * @param string $title The title. + * + * @return array Contains the modified title and alias. + * + * @since 1.6 + */ + protected function generateNewTitle($parent_id, $alias, $title) + { + // Alter the title & alias + $table = $this->getTable(); + while ($table->load(array('alias' => $alias, 'parent_id' => $parent_id))) + { + if ($title == $table->title) + { + $title = JString::increment($title); + } + $alias = JString::increment($alias, 'dash'); + } + + return array($title, $alias); + } + + /** + * Custom clean cache method + * + * @since 1.6 + */ + protected function cleanCache($group = null, $client_id = 0) + { + parent::cleanCache('com_modules'); + parent::cleanCache('mod_menu'); + } +} diff --git a/administrator/components/com_menus/models/items.php b/administrator/components/com_menus/models/items.php new file mode 100644 index 0000000..abdfeec --- /dev/null +++ b/administrator/components/com_menus/models/items.php @@ -0,0 +1,313 @@ +item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $config['filter_fields'][] = 'association'; + } + } + + parent::__construct($config); + } + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @return void + * @since 1.6 + */ + protected function populateState($ordering = null, $direction = null) + { + $app = JFactory::getApplication('administrator'); + + $search = $this->getUserStateFromRequest($this->context . '.search', 'filter_search'); + $this->setState('filter.search', $search); + + $published = $this->getUserStateFromRequest($this->context . '.published', 'filter_published', ''); + $this->setState('filter.published', $published); + + $access = $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access', 0, 'int'); + $this->setState('filter.access', $access); + + $parentId = $this->getUserStateFromRequest($this->context . '.filter.parent_id', 'filter_parent_id', 0, 'int'); + $this->setState('filter.parent_id', $parentId); + + $level = $this->getUserStateFromRequest($this->context . '.filter.level', 'filter_level', 0, 'int'); + $this->setState('filter.level', $level); + + $menuType = $app->input->getString('menutype', null); + if ($menuType) + { + if ($menuType != $app->getUserState($this->context . '.filter.menutype')) + { + $app->setUserState($this->context . '.filter.menutype', $menuType); + $app->input->set('limitstart', 0); + } + } + else + { + $menuType = $app->getUserState($this->context . '.filter.menutype'); + + if (!$menuType) + { + $menuType = $this->getDefaultMenuType(); + } + } + + $this->setState('filter.menutype', $menuType); + + $language = $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', ''); + $this->setState('filter.language', $language); + + // Component parameters. + $params = JComponentHelper::getParams('com_menus'); + $this->setState('params', $params); + + // List state information. + parent::populateState('a.lft', 'asc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + * @since 1.6 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.access'); + $id .= ':' . $this->getState('filter.published'); + $id .= ':' . $this->getState('filter.language'); + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.parent_id'); + $id .= ':' . $this->getState('filter.menutype'); + + return parent::getStoreId($id); + } + + /** + * Finds the default menu type. + * + * In the absence of better information, this is the first menu ordered by title. + * + * @return string The default menu type + * @since 1.6 + */ + protected function getDefaultMenuType() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->select('menutype') + ->from('#__menu_types') + ->order('title'); + $db->setQuery($query, 0, 1); + $menuType = $db->loadResult(); + + return $menuType; + } + + /** + * Builds an SQL query to load the list data. + * + * @return JDatabaseQuery A query object. + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + $user = JFactory::getUser(); + $app = JFactory::getApplication(); + + // Select all fields from the table. + $query->select( + $this->getState( + 'list.select', + $db->quoteName( + array('a.id', 'a.menutype', 'a.title', 'a.alias', 'a.note', 'a.path', 'a.link', 'a.type', 'a.parent_id', 'a.level', 'a.published', 'a.component_id', 'a.checked_out', 'a.checked_out_time', 'a.browserNav', 'a.access', 'a.img', 'a.template_style_id', 'a.params', 'a.lft', 'a.rgt', 'a.home', 'a.language', 'a.client_id'), + array(null, null, null, null, null, null, null, null, null, null, 'apublished', null, null, null, null, null, null, null, null, null, null, null, null, null) + ) + ) + ); + $query->select( + 'CASE a.type' . + ' WHEN ' . $db->quote('component') . ' THEN a.published+2*(e.enabled-1) ' . + ' WHEN ' . $db->quote('url') . ' THEN a.published+2 ' . + ' WHEN ' . $db->quote('alias') . ' THEN a.published+4 ' . + ' WHEN ' . $db->quote('separator') . ' THEN a.published+6 ' . + ' WHEN ' . $db->quote('heading') . ' THEN a.published+8 ' . + ' END AS published' + ); + $query->from($db->quoteName('#__menu') . ' AS a'); + + // Join over the language + $query->select('l.title AS language_title, l.image as image') + ->join('LEFT', $db->quoteName('#__languages') . ' AS l ON l.lang_code = a.language'); + + // Join over the users. + $query->select('u.name AS editor') + ->join('LEFT', $db->quoteName('#__users') . ' AS u ON u.id = a.checked_out'); + + //Join over components + $query->select('c.element AS componentname') + ->join('LEFT', $db->quoteName('#__extensions') . ' AS c ON c.extension_id = a.component_id'); + + // Join over the asset groups. + $query->select('ag.title AS access_level') + ->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access'); + + // Join over the associations. + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $query->select('COUNT(asso2.id)>1 as association') + ->join('LEFT', '#__associations AS asso ON asso.id = a.id AND asso.context=' . $db->quote('com_menus.item')) + ->join('LEFT', '#__associations AS asso2 ON asso2.key = asso.key') + ->group('a.id'); + } + + // Join over the extensions + $query->select('e.name AS name') + ->join('LEFT', '#__extensions AS e ON e.extension_id = a.component_id'); + + // Exclude the root category. + $query->where('a.id > 1') + ->where('a.client_id = 0'); + + // Filter on the published state. + $published = $this->getState('filter.published'); + if (is_numeric($published)) + { + $query->where('a.published = ' . (int) $published); + } + elseif ($published === '') + { + $query->where('(a.published IN (0, 1))'); + } + + // Filter by search in title, alias or id + if ($search = trim($this->getState('filter.search'))) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + elseif (stripos($search, 'link:') === 0) + { + if ($search = substr($search, 5)) + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('a.link LIKE ' . $search); + } + } + else + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('(' . 'a.title LIKE ' . $search . ' OR a.alias LIKE ' . $search . ' OR a.note LIKE ' . $search . ')'); + } + } + + // Filter the items over the parent id if set. + $parentId = $this->getState('filter.parent_id'); + if (!empty($parentId)) + { + $query->where('p.id = ' . (int) $parentId); + } + + // Filter the items over the menu id if set. + $menuType = $this->getState('filter.menutype'); + if (!empty($menuType)) + { + $query->where('a.menutype = ' . $db->quote($menuType)); + } + + // Filter on the access level. + if ($access = $this->getState('filter.access')) + { + $query->where('a.access = ' . (int) $access); + } + + // Implement View Level Access + if (!$user->authorise('core.admin')) + { + $groups = implode(',', $user->getAuthorisedViewLevels()); + $query->where('a.access IN (' . $groups . ')'); + } + + // Filter on the level. + if ($level = $this->getState('filter.level')) + { + $query->where('a.level <= ' . (int) $level); + } + + // Filter on the language. + if ($language = $this->getState('filter.language')) + { + $query->where('a.language = ' . $db->quote($language)); + } + + // Add the list ordering clause. + $query->order($db->escape($this->getState('list.ordering', 'a.lft')) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))); + + //echo nl2br(str_replace('#__','jos_',(string)$query)).'
    '; + return $query; + } +} diff --git a/administrator/components/com_menus/models/menu.php b/administrator/components/com_menus/models/menu.php new file mode 100644 index 0000000..57e36b7 --- /dev/null +++ b/administrator/components/com_menus/models/menu.php @@ -0,0 +1,296 @@ +authorise('core.delete', 'com_menus.menu.' . (int) $record->id); + } + + /** + * Method to test whether a record can be deleted. + * + * @param object A record object. + * + * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. + * @since 1.6 + */ + protected function canEditState($record) + { + $user = JFactory::getUser(); + + return $user->authorise('core.edit.state', 'com_menus.menu.' . (int) $record->id); + } + + /** + * Returns a Table object, always creating it + * + * @param type The table type to instantiate + * @param string A prefix for the table class name. Optional. + * @param array Configuration array for model. Optional. + * @return JTable A database object + */ + public function getTable($type = 'MenuType', $prefix = 'JTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @since 1.6 + */ + protected function populateState() + { + $app = JFactory::getApplication('administrator'); + + // Load the User state. + $id = $app->input->getInt('id'); + $this->setState('menu.id', $id); + + // Load the parameters. + $params = JComponentHelper::getParams('com_menus'); + $this->setState('params', $params); + } + + /** + * Method to get a menu item. + * + * @param integer The id of the menu item to get. + * + * @return mixed Menu item data object on success, false on failure. + */ + public function &getItem($itemId = null) + { + $itemId = (!empty($itemId)) ? $itemId : (int) $this->getState('menu.id'); + $false = false; + + // Get a menu item row instance. + $table = $this->getTable(); + + // Attempt to load the row. + $return = $table->load($itemId); + + // Check for a table object error. + if ($return === false && $table->getError()) + { + $this->setError($table->getError()); + return $false; + } + + $properties = $table->getProperties(1); + $value = JArrayHelper::toObject($properties, 'JObject'); + return $value; + } + + /** + * Method to get the menu item form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * @return JForm A JForm object on success, false on failure + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + // Get the form. + $form = $this->loadForm('com_menus.menu', 'menu', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_menus.edit.menu.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + } + + $this->preprocessData('com_menus.menu', $data); + + return $data; + } + + /** + * Method to save the form data. + * + * @param array The form data. + * @return boolean True on success. + */ + public function save($data) + { + $id = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('menu.id'); + + // Get a row instance. + $table = $this->getTable(); + + // Load the row if saving an existing item. + if ($id > 0) + { + $table->load($id); + } + + // Bind the data. + if (!$table->bind($data)) + { + $this->setError($table->getError()); + return false; + } + + // Check the data. + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // Store the data. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + $this->setState('menu.id', $table->id); + + // Clean the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to delete groups. + * + * @param array An array of item ids. + * @return boolean Returns true on success, false on failure. + */ + public function delete($itemIds) + { + // Sanitize the ids. + $itemIds = (array) $itemIds; + JArrayHelper::toInteger($itemIds); + + // Get a group row instance. + $table = $this->getTable(); + + // Iterate the items to delete each one. + foreach ($itemIds as $itemId) + { + // TODO: Delete the menu associations - Menu items and Modules + + if (!$table->delete($itemId)) + { + $this->setError($table->getError()); + return false; + } + } + + // Clean the cache + $this->cleanCache(); + + return true; + } + + /** + * Gets a list of all mod_mainmenu modules and collates them by menutype + * + * @return array + */ + public function &getModules() + { + $db = $this->getDbo(); + + $query = $db->getQuery(true) + ->from('#__modules as a') + ->select('a.id, a.title, a.params, a.position') + ->where('module = ' . $db->quote('mod_menu')) + ->select('ag.title AS access_title') + ->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access'); + $db->setQuery($query); + + $modules = $db->loadObjectList(); + + $result = array(); + + foreach ($modules as &$module) + { + $params = new JRegistry; + $params->loadString($module->params); + + $menuType = $params->get('menutype'); + if (!isset($result[$menuType])) + { + $result[$menuType] = array(); + } + $result[$menuType][] = & $module; + } + + return $result; + } + + /** + * Custom clean cache method + * + * @since 1.6 + */ + protected function cleanCache($group = null, $client_id = 0) + { + parent::cleanCache('com_modules'); + parent::cleanCache('mod_menu'); + } +} diff --git a/administrator/components/com_menus/models/menus.php b/administrator/components/com_menus/models/menus.php new file mode 100644 index 0000000..e3b9a46 --- /dev/null +++ b/administrator/components/com_menus/models/menus.php @@ -0,0 +1,235 @@ +getStoreId('getItems'); + + // Try to load the data from internal storage. + if (!empty($this->cache[$store])) + { + return $this->cache[$store]; + } + + // Load the list items. + $items = parent::getItems(); + + // If emtpy or an error, just return. + if (empty($items)) + { + return array(); + } + + // Getting the following metric by joins is WAY TOO SLOW. + // Faster to do three queries for very large menu trees. + + // Get the menu types of menus in the list. + $db = $this->getDbo(); + $menuTypes = JArrayHelper::getColumn($items, 'menutype'); + + // Quote the strings. + $menuTypes = implode( + ',', + array_map(array($db, 'quote'), $menuTypes) + ); + + // Get the published menu counts. + $query = $db->getQuery(true) + ->select('m.menutype, COUNT(DISTINCT m.id) AS count_published') + ->from('#__menu AS m') + ->where('m.published = 1') + ->where('m.menutype IN (' . $menuTypes . ')') + ->group('m.menutype'); + + $db->setQuery($query); + + try + { + $countPublished = $db->loadAssocList('menutype', 'count_published'); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + // Get the unpublished menu counts. + $query->clear('where') + ->where('m.published = 0') + ->where('m.menutype IN (' . $menuTypes . ')'); + $db->setQuery($query); + + try + { + $countUnpublished = $db->loadAssocList('menutype', 'count_published'); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + // Get the trashed menu counts. + $query->clear('where') + ->where('m.published = -2') + ->where('m.menutype IN (' . $menuTypes . ')'); + $db->setQuery($query); + + try + { + $countTrashed = $db->loadAssocList('menutype', 'count_published'); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage); + return false; + } + + // Inject the values back into the array. + foreach ($items as $item) + { + $item->count_published = isset($countPublished[$item->menutype]) ? $countPublished[$item->menutype] : 0; + $item->count_unpublished = isset($countUnpublished[$item->menutype]) ? $countUnpublished[$item->menutype] : 0; + $item->count_trashed = isset($countTrashed[$item->menutype]) ? $countTrashed[$item->menutype] : 0; + } + + // Add the items to the internal cache. + $this->cache[$store] = $items; + + return $this->cache[$store]; + } + + /** + * Method to build an SQL query to load the list data. + * + * @return string An SQL query + * + * @since 1.6 + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Select all fields from the table. + $query->select($this->getState('list.select', 'a.*')) + ->from($db->quoteName('#__menu_types') . ' AS a') + + ->group('a.id, a.menutype, a.title, a.description'); + + // Filter by search in title or menutype + if ($search = trim($this->getState('filter.search'))) + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('(' . 'a.title LIKE ' . $search . ' OR a.menutype LIKE ' . $search . ')'); + } + + // Add the list ordering clause. + $query->order($db->escape($this->getState('list.ordering', 'a.id')) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))); + + return $query; + } + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @param string $ordering An optional ordering field. + * @param string $direction An optional direction (asc|desc). + * + * @return void + * + * @since 1.6 + */ + protected function populateState($ordering = null, $direction = null) + { + $search = $this->getUserStateFromRequest($this->context . '.search', 'filter_search'); + $this->setState('filter.search', $search); + + // List state information. + parent::populateState('a.id', 'asc'); + } + + /** + * Gets the extension id of the core mod_menu module. + * + * @return integer + * + * @since 2.5 + */ + public function getModMenuId() + { + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->select('e.extension_id') + ->from('#__extensions AS e') + ->where('e.type = ' . $db->quote('module')) + ->where('e.element = ' . $db->quote('mod_menu')) + ->where('e.client_id = 0'); + $db->setQuery($query); + + return $db->loadResult(); + } + + /** + * Gets a list of all mod_mainmenu modules and collates them by menutype + * + * @return array + */ + public function &getModules() + { + $model = JModelLegacy::getInstance('Menu', 'MenusModel', array('ignore_request' => true)); + $result = & $model->getModules(); + + return $result; + } +} diff --git a/administrator/components/com_menus/models/menutypes.php b/administrator/components/com_menus/models/menutypes.php new file mode 100644 index 0000000..eb3dc00 --- /dev/null +++ b/administrator/components/com_menus/models/menutypes.php @@ -0,0 +1,431 @@ +rlu)) + { + $this->getTypeOptions(); + } + return $this->rlu; + } + + /** + * Method to get the available menu item type options. + * + * @return array Array of groups with menu item types. + * @since 1.6 + */ + public function getTypeOptions() + { + jimport('joomla.filesystem.file'); + + $lang = JFactory::getLanguage(); + $list = array(); + + // Get the list of components. + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('name, element AS ' . $db->quoteName('option')) + ->from('#__extensions') + ->where('type = ' . $db->quote('component')) + ->where('enabled = 1') + ->order('name ASC'); + $db->setQuery($query); + $components = $db->loadObjectList(); + + foreach ($components as $component) + { + if ($options = $this->getTypeOptionsByComponent($component->option)) + { + $list[$component->name] = $options; + + // Create the reverse lookup for link-to-name. + foreach ($options as $option) + { + if (isset($option->request)) + { + $this->addReverseLookupUrl($option); + + if (isset($option->request['option'])) + { + $lang->load($option->request['option'].'.sys', JPATH_ADMINISTRATOR, null, false, false) + || $lang->load($option->request['option'].'.sys', JPATH_ADMINISTRATOR.'/components/'.$option->request['option'], null, false, false) + || $lang->load($option->request['option'].'.sys', JPATH_ADMINISTRATOR, $lang->getDefault(), false, false) + || $lang->load($option->request['option'].'.sys', JPATH_ADMINISTRATOR.'/components/'.$option->request['option'], $lang->getDefault(), false, false); + } + } + } + } + } + + // Allow a system plugin to insert dynamic menu types to the list shown in menus: + JDispatcher::getInstance()->trigger('onAfterGetMenuTypeOptions', array(&$list, $this)); + + return $list; + } + + /** + * Method to create the reverse lookup for link-to-name. + * (can be used from onAfterGetMenuTypeOptions handlers) + * + * @param $option JObject with request array or string and title public variables + * + * @return void + * @since 3.1 + */ + public function addReverseLookupUrl($option) + { + $this->rlu[MenusHelper::getLinkKey($option->request)] = $option->get('title'); + } + + protected function getTypeOptionsByComponent($component) + { + $options = array(); + + $mainXML = JPATH_SITE.'/components/'.$component.'/metadata.xml'; + + if (is_file($mainXML)) + { + $options = $this->getTypeOptionsFromXML($mainXML, $component); + } + + if (empty($options)) + { + $options = $this->getTypeOptionsFromMVC($component); + } + + return $options; + } + + protected function getTypeOptionsFromXML($file, $component) + { + $options = array(); + + // Attempt to load the xml file. + if (!$xml = simplexml_load_file($file)) + { + return false; + } + + // Look for the first menu node off of the root node. + if (!$menu = $xml->xpath('menu[1]')) + { + return false; + } + else + { + $menu = $menu[0]; + } + + // If we have no options to parse, just add the base component to the list of options. + if (!empty($menu['options']) && $menu['options'] == 'none') + { + // Create the menu option for the component. + $o = new JObject; + $o->title = (string) $menu['name']; + $o->description = (string) $menu['msg']; + $o->request = array('option' => $component); + + $options[] = $o; + + return $options; + } + + // Look for the first options node off of the menu node. + if (!$optionsNode = $menu->xpath('options[1]')) + { + return false; + } + else + { + $optionsNode = $optionsNode[0]; + } + + // Make sure the options node has children. + if (!$children = $optionsNode->children()) + { + return false; + } + else + { + // Process each child as an option. + foreach ($children as $child) + { + if ($child->getName() == 'option') + { + // Create the menu option for the component. + $o = new JObject; + $o->title = (string) $child['name']; + $o->description = (string) $child['msg']; + $o->request = array('option' => $component, (string) $optionsNode['var'] => (string) $child['value']); + + $options[] = $o; + } + elseif ($child->getName() == 'default') + { + // Create the menu option for the component. + $o = new JObject; + $o->title = (string) $child['name']; + $o->description = (string) $child['msg']; + $o->request = array('option' => $component); + + $options[] = $o; + } + } + } + + return $options; + } + + protected function getTypeOptionsFromMVC($component) + { + $options = array(); + + // Get the views for this component. + $path = JPATH_SITE . '/components/' . $component . '/views'; + + if (is_dir($path)) + { + $views = JFolder::folders($path); + } + else + { + return false; + } + + foreach ($views as $view) + { + // Ignore private views. + if (strpos($view, '_') !== 0) + { + // Determine if a metadata file exists for the view. + $file = $path.'/'.$view.'/metadata.xml'; + + if (is_file($file)) + { + // Attempt to load the xml file. + if ($xml = simplexml_load_file($file)) + { + // Look for the first view node off of the root node. + if ($menu = $xml->xpath('view[1]')) + { + $menu = $menu[0]; + + // If the view is hidden from the menu, discard it and move on to the next view. + if (!empty($menu['hidden']) && $menu['hidden'] == 'true') + { + unset($xml); + continue; + } + + // Do we have an options node or should we process layouts? + // Look for the first options node off of the menu node. + if ($optionsNode = $menu->xpath('options[1]')) + { + $optionsNode = $optionsNode[0]; + + // Make sure the options node has children. + if ($children = $optionsNode->children()) + { + // Process each child as an option. + foreach ($children as $child) + { + if ($child->getName() == 'option') + { + // Create the menu option for the component. + $o = new JObject; + $o->title = (string) $child['name']; + $o->description = (string) $child['msg']; + $o->request = array('option' => $component, 'view' => $view, (string) $optionsNode['var'] => (string) $child['value']); + + $options[] = $o; + } + elseif ($child->getName() == 'default') + { + // Create the menu option for the component. + $o = new JObject; + $o->title = (string) $child['name']; + $o->description = (string) $child['msg']; + $o->request = array('option' => $component, 'view' => $view); + + $options[] = $o; + } + } + } + } + else { + $options = array_merge($options, (array) $this->getTypeOptionsFromLayouts($component, $view)); + } + } + unset($xml); + } + + } + else { + $options = array_merge($options, (array) $this->getTypeOptionsFromLayouts($component, $view)); + } + } + } + + return $options; + } + + protected function getTypeOptionsFromLayouts($component, $view) + { + $options = array(); + $layouts = array(); + $layoutNames = array(); + $lang = JFactory::getLanguage(); + + // Get the layouts from the view folder. + $path = JPATH_SITE . '/components/' . $component . '/views/' . $view . '/tmpl'; + if (is_dir($path)) + { + $layouts = array_merge($layouts, JFolder::files($path, '.xml$', false, true)); + } + else + { + return $options; + } + + // build list of standard layout names + foreach ($layouts as $layout) + { + // Ignore private layouts. + if (strpos(basename($layout), '_') === false) + { + // Get the layout name. + $layoutNames[] = basename($layout, '.xml'); + } + } + + // get the template layouts + // TODO: This should only search one template -- the current template for this item (default of specified) + $folders = JFolder::folders(JPATH_SITE . '/templates', '', false, true); + // Array to hold association between template file names and templates + $templateName = array(); + foreach ($folders as $folder) + { + if (is_dir($folder . '/html/' . $component . '/' . $view)) + { + $template = basename($folder); + $lang->load('tpl_'.$template.'.sys', JPATH_SITE, null, false, false) + || $lang->load('tpl_'.$template.'.sys', JPATH_SITE.'/templates/'.$template, null, false, false) + || $lang->load('tpl_'.$template.'.sys', JPATH_SITE, $lang->getDefault(), false, false) + || $lang->load('tpl_'.$template.'.sys', JPATH_SITE.'/templates/'.$template, $lang->getDefault(), false, false); + + $templateLayouts = JFolder::files($folder . '/html/' . $component . '/' . $view, '.xml$', false, true); + + foreach ($templateLayouts as $layout) + { + // Get the layout name. + $templateLayoutName = basename($layout, '.xml'); + + // add to the list only if it is not a standard layout + if (array_search($templateLayoutName, $layoutNames) === false) + { + $layouts[] = $layout; + // Set template name array so we can get the right template for the layout + $templateName[$layout] = basename($folder); + } + } + } + } + + // Process the found layouts. + foreach ($layouts as $layout) + { + // Ignore private layouts. + if (strpos(basename($layout), '_') === false) + { + $file = $layout; + // Get the layout name. + $layout = basename($layout, '.xml'); + + // Create the menu option for the layout. + $o = new JObject; + $o->title = ucfirst($layout); + $o->description = ''; + $o->request = array('option' => $component, 'view' => $view); + + // Only add the layout request argument if not the default layout. + if ($layout != 'default') + { + // If the template is set, add in format template:layout so we save the template name + $o->request['layout'] = (isset($templateName[$file])) ? $templateName[$file] . ':' . $layout : $layout; + } + + // Load layout metadata if it exists. + if (is_file($file)) + { + // Attempt to load the xml file. + if ($xml = simplexml_load_file($file)) + { + // Look for the first view node off of the root node. + if ($menu = $xml->xpath('layout[1]')) + { + $menu = $menu[0]; + + // If the view is hidden from the menu, discard it and move on to the next view. + if (!empty($menu['hidden']) && $menu['hidden'] == 'true') + { + unset($xml); + unset($o); + continue; + } + + // Populate the title and description if they exist. + if (!empty($menu['title'])) + { + $o->title = trim((string) $menu['title']); + } + + if (!empty($menu->message[0])) + { + $o->description = trim((string) $menu->message[0]); + } + } + } + } + + // Add the layout to the options array. + $options[] = $o; + } + } + + return $options; + } +} diff --git a/administrator/components/com_menus/tables/index.html b/administrator/components/com_menus/tables/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/tables/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/tables/menu.php b/administrator/components/com_menus/tables/menu.php new file mode 100644 index 0000000..4c568c9 --- /dev/null +++ b/administrator/components/com_menus/tables/menu.php @@ -0,0 +1,35 @@ + diff --git a/administrator/components/com_menus/views/item/index.html b/administrator/components/com_menus/views/item/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/views/item/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/views/item/tmpl/edit.php b/administrator/components/com_menus/views/item/tmpl/edit.php new file mode 100644 index 0000000..0a8768b --- /dev/null +++ b/administrator/components/com_menus/views/item/tmpl/edit.php @@ -0,0 +1,292 @@ +item_associations) ? $app->item_associations : 0; + +?> + + + + + +
    + 'details')); ?> + + +
    +
    +
    +
    + form->getLabel('type'); ?> +
    +
    + form->getInput('type'); ?> +
    +
    + item->type == 'url') : ?> + form->setFieldAttribute('link', 'readonly', 'false');?> +
    +
    + form->getLabel('link'); ?> +
    +
    + form->getInput('link'); ?> +
    +
    + + + item->link == 'index.php?Itemid=') : ?> + form->getFieldsets('params'); ?> + form->getFieldset('aliasoptions') as $field) : ?> +
    +
    + label; ?> +
    +
    + input; ?> +
    +
    + + + + item->link == 'index.php?option=com_wrapper&view=wrapper') : ?> + form->getFieldsets('params'); ?> + form->getFieldset('request') as $field) : ?> +
    +
    + label; ?> +
    +
    + input; ?> +
    +
    + + + + form->getFieldsets('request'); + + if (!empty($fieldSets)) : + $fieldSet = array_shift($fieldSets); + $label = !empty($fieldSet->label) ? $fieldSet->label : 'COM_MENUS_' . $fieldSet->name . '_FIELDSET_LABEL'; + if (isset($fieldSet->description) && trim($fieldSet->description)) : + echo '

    ' . $this->escape(JText::_($fieldSet->description)) . '

    '; + endif; + ?> + + form->getFieldset('request') as $field) : ?> + hidden) : ?> +
    +
    + label; ?> +
    +
    + input; ?> +
    +
    + input; ?> + + + + +
    +
    + form->getLabel('title'); ?> +
    +
    + form->getInput('title'); ?> +
    +
    + item->type == 'alias') : ?> +
    +
    + form->getLabel('aliastip'); ?> +
    +
    + + item->type != 'url') : ?> +
    +
    + form->getLabel('alias'); ?> +
    +
    + form->getInput('alias'); ?> +
    +
    + +
    +
    +
    + form->getLabel('published'); ?> +
    +
    + form->getInput('published'); ?> +
    +
    + item->type !== 'url') : ?> +
    +
    + form->getLabel('link'); ?> +
    +
    + form->getInput('link'); ?> +
    +
    + +
    +
    + form->getLabel('menutype'); ?> +
    +
    + form->getInput('menutype'); ?> +
    +
    +
    +
    + form->getLabel('parent_id'); ?> +
    +
    + form->getInput('parent_id'); ?> +
    +
    +
    +
    + form->getLabel('menuordering'); ?> +
    +
    + form->getInput('menuordering'); ?> +
    +
    +
    +
    +
    +
    + form->getLabel('access'); ?> +
    +
    + form->getInput('access'); ?> +
    +
    + item->type == 'component') : ?> +
    +
    + form->getLabel('home'); ?> +
    +
    + form->getInput('home'); ?> +
    +
    + +
    +
    + form->getLabel('browserNav'); ?> +
    +
    + form->getInput('browserNav'); ?> +
    +
    +
    +
    + form->getLabel('template_style_id'); ?> +
    +
    + form->getInput('template_style_id'); ?> +
    +
    +
    +
    + form->getLabel('language'); ?> +
    +
    + form->getInput('language'); ?> +
    +
    +
    +
    + form->getLabel('note'); ?> +
    +
    + form->getInput('note'); ?> +
    +
    +
    +
    + form->getLabel('id'); ?> +
    +
    + form->getInput('id'); ?> +
    +
    +
    +
    + + + + loadTemplate('options'); ?> + + + + + loadTemplate('associations'); ?> + + + + modules)) : ?> + + loadTemplate('modules'); ?> + + + + +
    + + + form->getInput('component_id'); ?> + + +
    diff --git a/administrator/components/com_menus/views/item/tmpl/edit_associations.php b/administrator/components/com_menus/views/item/tmpl/edit_associations.php new file mode 100644 index 0000000..5d1c1f6 --- /dev/null +++ b/administrator/components/com_menus/views/item/tmpl/edit_associations.php @@ -0,0 +1,12 @@ +addScriptDeclaration(implode("\n", $script)); +?> + +
    +
    + +
    +
    + +
    +
    + + + + + + + + + + modules as $i => &$module) : ?> + menuid)) : ?> + except || $module->menuid < 0) : ?> + + + + + + + + + + +
    + + + +
    + id . '&tmpl=component&view=module&layout=modal'; ?> + + escape($module->title), $this->escape($module->access_title), $this->escape($module->position)); ?> + + menuid)) : ?> + except):?> + + + + + + + + + menuid > 0) : ?> + + + + menuid < 0) : ?> + + + + + + + + +
    diff --git a/administrator/components/com_menus/views/item/tmpl/edit_options.php b/administrator/components/com_menus/views/item/tmpl/edit_options.php new file mode 100644 index 0000000..250f6c7 --- /dev/null +++ b/administrator/components/com_menus/views/item/tmpl/edit_options.php @@ -0,0 +1,44 @@ + + 'collapse0')); + $fieldSets = $this->form->getFieldsets('params'); + $i = 0; + + foreach ($fieldSets as $name => $fieldSet) : + if (!(($this->item->link == 'index.php?option=com_wrapper&view=wrapper') && $fieldSet->name == 'request') + && !($this->item->link == 'index.php?Itemid=' && $fieldSet->name == 'aliasoptions')) : + $label = !empty($fieldSet->label) ? $fieldSet->label : 'COM_MENUS_'.$name.'_FIELDSET_LABEL'; + echo JHtml::_('bootstrap.addSlide', 'menuOptions', JText::_($label), 'collapse' . $i++); + if (isset($fieldSet->description) && trim($fieldSet->description)) : + echo '

    '.$this->escape(JText::_($fieldSet->description)).'

    '; + endif; + ?> + form->getFieldset($name) as $field) : ?> + +
    + +
    + label; ?> +
    +
    + input; ?> +
    + +
    + + diff --git a/administrator/components/com_menus/views/item/view.html.php b/administrator/components/com_menus/views/item/view.html.php new file mode 100644 index 0000000..47e75ea --- /dev/null +++ b/administrator/components/com_menus/views/item/view.html.php @@ -0,0 +1,123 @@ +form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->modules = $this->get('Modules'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + parent::display($tpl); + $this->addToolbar(); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + $input = JFactory::getApplication()->input; + $input->set('hidemainmenu', true); + + $user = JFactory::getUser(); + $isNew = ($this->item->id == 0); + $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $user->get('id')); + $canDo = MenusHelper::getActions($this->state->get('filter.parent_id')); + + JToolbarHelper::title(JText::_($isNew ? 'COM_MENUS_VIEW_NEW_ITEM_TITLE' : 'COM_MENUS_VIEW_EDIT_ITEM_TITLE'), 'menu-add'); + + // If a new item, can save the item. Allow users with edit permissions to apply changes to prevent returning to grid. + if ($isNew && $canDo->get('core.create')) + { + if ($canDo->get('core.edit')) + { + JToolbarHelper::apply('item.apply'); + } + JToolbarHelper::save('item.save'); + } + + // If not checked out, can save the item. + if (!$isNew && !$checkedOut && $canDo->get('core.edit')) + { + JToolbarHelper::apply('item.apply'); + JToolbarHelper::save('item.save'); + } + + // If the user can create new items, allow them to see Save & New + if ($canDo->get('core.create')) + { + JToolbarHelper::save2new('item.save2new'); + } + + // If an existing item, can save to a copy only if we have create rights. + if (!$isNew && $canDo->get('core.create')) + { + JToolbarHelper::save2copy('item.save2copy'); + } + + if ($isNew) + { + JToolbarHelper::cancel('item.cancel'); + } + else + { + JToolbarHelper::cancel('item.cancel', 'JTOOLBAR_CLOSE'); + } + + JToolbarHelper::divider(); + + // Get the help information for the menu item. + $lang = JFactory::getLanguage(); + + $help = $this->get('Help'); + if ($lang->hasKey($help->url)) + { + $debug = $lang->setDebug(false); + $url = JText::_($help->url); + $lang->setDebug($debug); + } + else + { + $url = $help->url; + } + JToolbarHelper::help($help->key, $help->local, $url); + } +} diff --git a/administrator/components/com_menus/views/items/index.html b/administrator/components/com_menus/views/items/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/views/items/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/views/items/tmpl/default.php b/administrator/components/com_menus/views/items/tmpl/default.php new file mode 100644 index 0000000..6ceb482 --- /dev/null +++ b/administrator/components/com_menus/views/items/tmpl/default.php @@ -0,0 +1,276 @@ +get('id'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$ordering = ($listOrder == 'a.lft'); +$canOrder = $user->authorise('core.edit.state', 'com_menus'); +$saveOrder = ($listOrder == 'a.lft' && $listDirn == 'asc'); +if ($saveOrder) +{ + $saveOrderingUrl = 'index.php?option=com_menus&task=items.saveOrderAjax&tmpl=component'; + JHtml::_('sortablelist.sortable', 'itemList', 'adminForm', strtolower($listDirn), $saveOrderingUrl, false, true); +} +$sortFields = $this->getSortFields(); +$assoc = isset($app->item_associations) ? $app->item_associations : 0; +?> + + +
    +sidebar)) : ?> +
    + sidebar; ?> +
    +
    + +
    + +
    + +
    + + +
    +
    + + pagination->getLimitBox(); ?> +
    +
    + + +
    +
    + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + items as $i => $item) : + $orderkey = array_search($item->id, $this->ordering[$item->parent_id]); + $canCreate = $user->authorise('core.create', 'com_menus'); + $canEdit = $user->authorise('core.edit', 'com_menus'); + $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id')|| $item->checked_out == 0; + $canChange = $user->authorise('core.edit.state', 'com_menus') && $canCheckin; + // Get the parents of item for sorting + if ($item->level > 1) + { + $parentsStr = ""; + $_currentParentId = $item->parent_id; + $parentsStr = " ".$_currentParentId; + for ($j = 0; $j < $item->level; $j++) + { + foreach ($this->ordering as $k => $v) + { + $v = implode("-", $v); + $v = "-" . $v . "-"; + if (strpos($v, "-" . $_currentParentId . "-") !== false) + { + $parentsStr .= " " . $k; + $_currentParentId = $k; + break; + } + } + } + } + else + { + $parentsStr = ""; + } + ?> + + + + + + + + + + + + + + + +
    + ', 'a.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING'); ?> + + + + + + + + + + + + + + state->get('list.direction'), $this->state->get('list.ordering')); ?> + + +
    + pagination->getListFooter(); ?> +
    + + + + + + + + + id); ?> + + published, $i, $canChange, 'cb'); ?> + + |—', $item->level - 1) ?> + checked_out) : ?> + editor, $item->checked_out_time, 'items.', $canCheckin); ?> + + + + escape($item->title); ?> + + escape($item->title); ?> + + + type != 'url') : ?> + note)) : ?> + escape($item->alias));?> + + escape($item->alias), $this->escape($item->note));?> + + type == 'url' && $item->note) : ?> + escape($item->note));?> + + +
    + —', $item->level - 1) ?> + + escape($item->item_type); ?> +
    +
    + type == 'component') : ?> + language == '*' || $item->home == '0'):?> + home, $i, 'items.', ($item->language != '*' || !$item->home) && $canChange);?> + + + image . '.gif', $item->language_title, array('title' => JText::sprintf('COM_MENUS_GRID_UNSET_LANGUAGE', $item->language_title)), true);?> + + + image . '.gif', $item->language_title, array('title' => $item->language_title), true);?> + + + + escape($item->access_level); ?> + + association):?> + id);?> + + + language == ''):?> + + language == '*'):?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + + id; ?> +
    + + authorise('core.create', 'com_menus') || $user->authorise('core.edit', 'com_menus')) : ?> + loadTemplate('batch'); ?> + + + + + + + + +
    + diff --git a/administrator/components/com_menus/views/items/tmpl/default_batch.php b/administrator/components/com_menus/views/items/tmpl/default_batch.php new file mode 100644 index 0000000..44047ef --- /dev/null +++ b/administrator/components/com_menus/views/items/tmpl/default_batch.php @@ -0,0 +1,64 @@ +state->get('filter.published'); +?> + diff --git a/administrator/components/com_menus/views/items/tmpl/index.html b/administrator/components/com_menus/views/items/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/views/items/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/views/items/view.html.php b/administrator/components/com_menus/views/items/view.html.php new file mode 100644 index 0000000..20ec7d1 --- /dev/null +++ b/administrator/components/com_menus/views/items/view.html.php @@ -0,0 +1,309 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + MenusHelper::addSubmenu('items'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->ordering = array(); + + // Preprocess the list of items to find ordering divisions. + foreach ($this->items as $item) + { + $this->ordering[$item->parent_id][] = $item->id; + + // item type text + switch ($item->type) + { + case 'url': + $value = JText::_('COM_MENUS_TYPE_EXTERNAL_URL'); + break; + + case 'alias': + $value = JText::_('COM_MENUS_TYPE_ALIAS'); + break; + + case 'separator': + $value = JText::_('COM_MENUS_TYPE_SEPARATOR'); + break; + + case 'heading': + $value = JText::_('COM_MENUS_TYPE_HEADING'); + break; + + case 'component': + default: + // load language + $lang->load($item->componentname.'.sys', JPATH_ADMINISTRATOR, null, false, false) + || $lang->load($item->componentname.'.sys', JPATH_ADMINISTRATOR.'/components/'.$item->componentname, null, false, false) + || $lang->load($item->componentname.'.sys', JPATH_ADMINISTRATOR, $lang->getDefault(), false, false) + || $lang->load($item->componentname.'.sys', JPATH_ADMINISTRATOR.'/components/'.$item->componentname, $lang->getDefault(), false, false); + + if (!empty($item->componentname)) + { + $value = JText::_($item->componentname); + $vars = null; + + parse_str($item->link, $vars); + if (isset($vars['view'])) + { + // Attempt to load the view xml file. + $file = JPATH_SITE.'/components/'.$item->componentname.'/views/'.$vars['view'].'/metadata.xml'; + if (is_file($file) && $xml = simplexml_load_file($file)) + { + // Look for the first view node off of the root node. + if ($view = $xml->xpath('view[1]')) + { + if (!empty($view[0]['title'])) + { + $vars['layout'] = isset($vars['layout']) ? $vars['layout'] : 'default'; + + // Attempt to load the layout xml file. + // If Alternative Menu Item, get template folder for layout file + if (strpos($vars['layout'], ':') > 0) + { + // Use template folder for layout file + $temp = explode(':', $vars['layout']); + $file = JPATH_SITE.'/templates/'.$temp[0].'/html/'.$item->componentname.'/'.$vars['view'].'/'.$temp[1].'.xml'; + // Load template language file + $lang->load('tpl_'.$temp[0].'.sys', JPATH_SITE, null, false, false) + || $lang->load('tpl_'.$temp[0].'.sys', JPATH_SITE.'/templates/'.$temp[0], null, false, false) + || $lang->load('tpl_'.$temp[0].'.sys', JPATH_SITE, $lang->getDefault(), false, false) + || $lang->load('tpl_'.$temp[0].'.sys', JPATH_SITE.'/templates/'.$temp[0], $lang->getDefault(), false, false); + + } + else + { + // Get XML file from component folder for standard layouts + $file = JPATH_SITE.'/components/'.$item->componentname.'/views/'.$vars['view'].'/tmpl/'.$vars['layout'].'.xml'; + } + if (is_file($file) && $xml = simplexml_load_file($file)) + { + // Look for the first view node off of the root node. + if ($layout = $xml->xpath('layout[1]')) + { + if (!empty($layout[0]['title'])) + { + $value .= ' » ' . JText::_(trim((string) $layout[0]['title'])); + } + } + if (!empty($layout[0]->message[0])) + { + $item->item_type_desc = JText::_(trim((string) $layout[0]->message[0])); + } + } + } + } + unset($xml); + } + else + { + // Special case for absent views + $value .= ' » ' . $vars['view']; + } + } + } + else + { + if (preg_match("/^index.php\?option=([a-zA-Z\-0-9_]*)/", $item->link, $result)) + { + $value = JText::sprintf('COM_MENUS_TYPE_UNEXISTING', $result[1]); + } + else { + $value = JText::_('COM_MENUS_TYPE_UNKNOWN'); + } + } + break; + } + $item->item_type = $value; + } + + // Levels filter. + $options = array(); + $options[] = JHtml::_('select.option', '1', JText::_('J1')); + $options[] = JHtml::_('select.option', '2', JText::_('J2')); + $options[] = JHtml::_('select.option', '3', JText::_('J3')); + $options[] = JHtml::_('select.option', '4', JText::_('J4')); + $options[] = JHtml::_('select.option', '5', JText::_('J5')); + $options[] = JHtml::_('select.option', '6', JText::_('J6')); + $options[] = JHtml::_('select.option', '7', JText::_('J7')); + $options[] = JHtml::_('select.option', '8', JText::_('J8')); + $options[] = JHtml::_('select.option', '9', JText::_('J9')); + $options[] = JHtml::_('select.option', '10', JText::_('J10')); + + $this->f_levels = $options; + + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + + // Allow a system plugin to insert dynamic menu types to the list shown in menus: + JDispatcher::getInstance()->trigger('onBeforeRenderMenuItems', array($this)); + + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + require_once JPATH_COMPONENT.'/helpers/menus.php'; + + $canDo = MenusHelper::getActions($this->state->get('filter.parent_id')); + $user = JFactory::getUser(); + + // Get the toolbar object instance + $bar = JToolBar::getInstance('toolbar'); + + JToolbarHelper::title(JText::_('COM_MENUS_VIEW_ITEMS_TITLE'), 'menumgr.png'); + + if ($canDo->get('core.create')) + { + JToolbarHelper::addNew('item.add'); + } + + if ($canDo->get('core.edit')) + { + JToolbarHelper::editList('item.edit'); + } + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::publish('items.publish', 'JTOOLBAR_PUBLISH', true); + JToolbarHelper::unpublish('items.unpublish', 'JTOOLBAR_UNPUBLISH', true); + } + if (JFactory::getUser()->authorise('core.admin')) + { + JToolbarHelper::checkin('items.checkin', 'JTOOLBAR_CHECKIN', true); + } + + if ($this->state->get('filter.published') == -2 && $canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'items.delete', 'JTOOLBAR_EMPTY_TRASH'); + } + elseif ($canDo->get('core.edit.state')) + { + JToolbarHelper::trash('items.trash'); + } + + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::makeDefault('items.setDefault', 'COM_MENUS_TOOLBAR_SET_HOME'); + } + if (JFactory::getUser()->authorise('core.admin')) + { + JToolbarHelper::custom('items.rebuild', 'refresh.png', 'refresh_f2.png', 'JToolbar_Rebuild', false); + } + + // Add a batch button + if ($user->authorise('core.create', 'com_menus') && $user->authorise('core.edit', 'com_menus') && $user->authorise('core.edit.state', 'com_menus')) + { + JHtml::_('bootstrap.modal', 'collapseModal'); + $title = JText::_('JTOOLBAR_BATCH'); + + // Instantiate a new JLayoutFile instance and render the batch button + $layout = new JLayoutFile('joomla.toolbar.batch'); + + $dhtml = $layout->render(array('title' => $title)); + $bar->appendButton('Custom', $dhtml, 'batch'); + } + + JToolbarHelper::help('JHELP_MENUS_MENU_ITEM_MANAGER'); + + JHtmlSidebar::setAction('index.php?option=com_menus&view=items'); + + JHtmlSidebar::addFilter( + // @todo we need a label here + '', + 'menutype', + JHtml::_('select.options', JHtml::_('menu.menus'), 'value', 'text', $this->state->get('filter.menutype')), + false + ); + + JHtmlSidebar::addFilter( + JText::_('COM_MENUS_OPTION_SELECT_LEVEL'), + 'filter_level', + JHtml::_('select.options', $this->f_levels, 'value', 'text', $this->state->get('filter.level')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_published', + JHtml::_('select.options', JHtml::_('jgrid.publishedOptions', array('archived' => false)), 'value', 'text', $this->state->get('filter.published'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_ACCESS'), + 'filter_access', + JHtml::_('select.options', JHtml::_('access.assetgroups'), 'value', 'text', $this->state->get('filter.access')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_LANGUAGE'), + 'filter_language', + JHtml::_('select.options', JHtml::_('contentlanguage.existing', true, true), 'value', 'text', $this->state->get('filter.language')) + ); + } + + /** + * Returns an array of fields the table can be sorted by + * + * @return array Array containing the field name to sort by as the key and display text as value + * + * @since 3.0 + */ + protected function getSortFields() + { + return array( + 'a.lft' => JText::_('JGRID_HEADING_ORDERING'), + 'a.published' => JText::_('JSTATUS'), + 'a.title' => JText::_('JGLOBAL_TITLE'), + 'a.home' => JText::_('COM_MENUS_HEADING_HOME'), + 'a.access' => JText::_('JGRID_HEADING_ACCESS'), + 'association' => JText::_('COM_MENUS_HEADING_ASSOCIATION'), + 'language' => JText::_('JGRID_HEADING_LANGUAGE'), + 'a.id' => JText::_('JGRID_HEADING_ID') + ); + } +} diff --git a/administrator/components/com_menus/views/menu/index.html b/administrator/components/com_menus/views/menu/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/views/menu/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/views/menu/tmpl/edit.php b/administrator/components/com_menus/views/menu/tmpl/edit.php new file mode 100644 index 0000000..a015763 --- /dev/null +++ b/administrator/components/com_menus/views/menu/tmpl/edit.php @@ -0,0 +1,59 @@ + + + + +
    +
    + +
    +
    + form->getLabel('title'); ?> +
    +
    + form->getInput('title'); ?> +
    +
    +
    +
    + form->getLabel('menutype'); ?> +
    +
    + form->getInput('menutype'); ?> +
    +
    +
    +
    + form->getLabel('description'); ?> +
    +
    + form->getInput('description'); ?> +
    +
    +
    + + +
    diff --git a/administrator/components/com_menus/views/menu/tmpl/index.html b/administrator/components/com_menus/views/menu/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/views/menu/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/views/menu/view.html.php b/administrator/components/com_menus/views/menu/view.html.php new file mode 100644 index 0000000..f2979e5 --- /dev/null +++ b/administrator/components/com_menus/views/menu/view.html.php @@ -0,0 +1,95 @@ +form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + parent::display($tpl); + $this->addToolbar(); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + $input = JFactory::getApplication()->input; + $input->set('hidemainmenu', true); + + $isNew = ($this->item->id == 0); + $canDo = MenusHelper::getActions($this->state->get('filter.parent_id')); + + JToolbarHelper::title(JText::_($isNew ? 'COM_MENUS_VIEW_NEW_MENU_TITLE' : 'COM_MENUS_VIEW_EDIT_MENU_TITLE'), 'menu.png'); + + // If a new item, can save the item. Allow users with edit permissions to apply changes to prevent returning to grid. + if ($isNew && $canDo->get('core.create')) + { + if ($canDo->get('core.edit')) + { + JToolbarHelper::apply('menu.apply'); + } + JToolbarHelper::save('menu.save'); + } + + // If user can edit, can save the item. + if (!$isNew && $canDo->get('core.edit')) + { + JToolbarHelper::apply('menu.apply'); + JToolbarHelper::save('menu.save'); + } + + // If the user can create new items, allow them to see Save & New + if ($canDo->get('core.create')) + { + JToolbarHelper::save2new('menu.save2new'); + } + if ($isNew) + { + JToolbarHelper::cancel('menu.cancel'); + } + else + { + JToolbarHelper::cancel('menu.cancel', 'JTOOLBAR_CLOSE'); + } + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_MENUS_MENU_MANAGER_EDIT'); + } +} diff --git a/administrator/components/com_menus/views/menus/index.html b/administrator/components/com_menus/views/menus/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/views/menus/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/views/menus/tmpl/default.php b/administrator/components/com_menus/views/menus/tmpl/default.php new file mode 100644 index 0000000..214be40 --- /dev/null +++ b/administrator/components/com_menus/views/menus/tmpl/default.php @@ -0,0 +1,167 @@ +get('id'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$modMenuId = (int) $this->get('ModMenuId'); +?> + +
    +sidebar)) : ?> +
    + sidebar; ?> +
    +
    + +
    + +
    + +
    + + +
    +
    + + pagination->getLimitBox(); ?> +
    +
    +
    + + + + + + + + + + + + + + + + + + + items as $i => $item) : + $canCreate = $user->authorise('core.create', 'com_menus'); + $canEdit = $user->authorise('core.edit', 'com_menus'); + $canChange = $user->authorise('core.edit.state', 'com_menus'); + ?> + + + + + + + + + + + +
    + + + + + + + + + + + + + +
    + pagination->getListFooter(); ?> +
    + id); ?> + + + escape($item->title); ?> +

    ( + + id).' title='.$this->escape($item->description).'">'. + $this->escape($item->menutype).''; ?>) + + escape($item->menutype)?>) + +

    +
    + + count_published; ?> + + + count_unpublished; ?> + + + count_trashed; ?> + + modules[$item->menutype])) : ?> +
    + + + + + +
    + + + + +
    + id; ?> +
    + + + + + + +
    + diff --git a/administrator/components/com_menus/views/menus/tmpl/index.html b/administrator/components/com_menus/views/menus/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_menus/views/menus/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_menus/views/menus/view.html.php b/administrator/components/com_menus/views/menus/view.html.php new file mode 100644 index 0000000..d7dcbb3 --- /dev/null +++ b/administrator/components/com_menus/views/menus/view.html.php @@ -0,0 +1,89 @@ +items = $this->get('Items'); + $this->modules = $this->get('Modules'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + MenusHelper::addSubmenu('menus'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + require_once JPATH_COMPONENT.'/helpers/menus.php'; + + $canDo = MenusHelper::getActions($this->state->get('filter.parent_id')); + + JToolbarHelper::title(JText::_('COM_MENUS_VIEW_MENUS_TITLE'), 'menumgr.png'); + + if ($canDo->get('core.create')) + { + JToolbarHelper::addNew('menu.add'); + } + if ($canDo->get('core.edit')) + { + JToolbarHelper::editList('menu.edit'); + } + if ($canDo->get('core.delete')) + { + JToolbarHelper::divider(); + JToolbarHelper::deleteList('', 'menus.delete'); + } + + JToolbarHelper::custom('menus.rebuild', 'refresh.png', 'refresh_f2.png', 'JTOOLBAR_REBUILD', false); + if ($canDo->get('core.admin')) + { + JToolbarHelper::divider(); + JToolbarHelper::preferences('com_menus'); + } + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_MENUS_MENU_MANAGER'); + } +} diff --git a/administrator/components/com_menus/views/menutypes/index.html b/administrator/components/com_menus/views/menutypes/index.html new file mode 100644 index 0000000..42682b4 --- /dev/null +++ b/administrator/components/com_menus/views/menutypes/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_menus/views/menutypes/tmpl/default.php b/administrator/components/com_menus/views/menutypes/tmpl/default.php new file mode 100644 index 0000000..121a938 --- /dev/null +++ b/administrator/components/com_menus/views/menutypes/tmpl/default.php @@ -0,0 +1,71 @@ +input; +// Checking if loaded via index.php or component.php +$tmpl = $input->getCmd('tmpl', ''); +$document = JFactory::getDocument(); +?> + + + + 'slide1')); ?> + types as $name => $list) : ?> + + + + + + + + diff --git a/administrator/components/com_menus/views/menutypes/tmpl/index.html b/administrator/components/com_menus/views/menutypes/tmpl/index.html new file mode 100644 index 0000000..42682b4 --- /dev/null +++ b/administrator/components/com_menus/views/menutypes/tmpl/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_menus/views/menutypes/view.html.php b/administrator/components/com_menus/views/menutypes/view.html.php new file mode 100644 index 0000000..ba215c1 --- /dev/null +++ b/administrator/components/com_menus/views/menutypes/view.html.php @@ -0,0 +1,55 @@ +input; + $this->recordId = $input->getInt('recordId'); + $this->types = $this->get('TypeOptions'); + + $this->addToolbar(); + + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 3.0 + */ + protected function addToolbar() + { + // Add page title + JToolbarHelper::title(JText::_('COM_MENUS'), 'menumgr.png'); + + // Get the toolbar object instance + $bar = JToolBar::getInstance('toolbar'); + + // Cancel + $title = JText::_('JTOOLBAR_CANCEL'); + $dhtml = ""; + $bar->appendButton('Custom', $dhtml, 'new'); + } +} diff --git a/administrator/components/com_messages/access.xml b/administrator/components/com_messages/access.xml new file mode 100644 index 0000000..db0d199 --- /dev/null +++ b/administrator/components/com_messages/access.xml @@ -0,0 +1,10 @@ + + +
    + + + + + +
    +
    diff --git a/administrator/components/com_messages/config.xml b/administrator/components/com_messages/config.xml new file mode 100644 index 0000000..38c31c0 --- /dev/null +++ b/administrator/components/com_messages/config.xml @@ -0,0 +1,18 @@ + + +
    + + +
    +
    diff --git a/administrator/components/com_messages/controller.php b/administrator/components/com_messages/controller.php new file mode 100644 index 0000000..a63b9ab --- /dev/null +++ b/administrator/components/com_messages/controller.php @@ -0,0 +1,54 @@ +input->get('view', 'messages'); + $layout = $this->input->get('layout', 'default'); + $id = $this->input->getInt('id'); + + // Check for edit form. + if ($view == 'message' && $layout == 'edit' && !$this->checkEditId('com_messages.edit.message', $id)) + { + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_messages&view=messages', false)); + + return false; + } + + // Load the submenu. + MessagesHelper::addSubmenu($this->input->get('view', 'messages')); + parent::display(); + + } +} diff --git a/administrator/components/com_messages/controllers/config.php b/administrator/components/com_messages/controllers/config.php new file mode 100644 index 0000000..fa43011 --- /dev/null +++ b/administrator/components/com_messages/controllers/config.php @@ -0,0 +1,79 @@ +getModel('Config', 'MessagesModel'); + $data = $this->input->post->get('jform', array(), 'array'); + + // Validate the posted data. + $form = $model->getForm(); + if (!$form) + { + JError::raiseError(500, $model->getError()); + return false; + } + $data = $model->validate($form, $data); + + // Check for validation errors. + if ($data === false) + { + // Get the validation messages. + $errors = $model->getErrors(); + + // Push up to three validation messages out to the user. + for ($i = 0, $n = count($errors); $i < $n && $i < 3; $i++) + { + if ($errors[$i] instanceof Exception) + { + $app->enqueueMessage($errors[$i]->getMessage(), 'warning'); + } else { + $app->enqueueMessage($errors[$i], 'warning'); + } + } + + // Redirect back to the main list. + $this->setRedirect(JRoute::_('index.php?option=com_messages&view=messages', false)); + return false; + } + + // Attempt to save the data. + if (!$model->save($data)) + { + // Redirect back to the main list. + $this->setMessage(JText::sprintf('JERROR_SAVE_FAILED', $model->getError()), 'warning'); + $this->setRedirect(JRoute::_('index.php?option=com_messages&view=messages', false)); + return false; + } + + // Redirect to the list screen. + $this->setMessage(JText::_('COM_MESSAGES_CONFIG_SAVED')); + $this->setRedirect(JRoute::_('index.php?option=com_messages&view=messages', false)); + + return true; + } +} diff --git a/administrator/components/com_messages/controllers/index.html b/administrator/components/com_messages/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/controllers/message.php b/administrator/components/com_messages/controllers/message.php new file mode 100644 index 0000000..b7bc64f --- /dev/null +++ b/administrator/components/com_messages/controllers/message.php @@ -0,0 +1,53 @@ +input->getInt('reply_id')) + { + $this->setRedirect('index.php?option=com_messages&view=message&layout=edit&reply_id=' . $replyId); + } + else + { + $this->setMessage(JText::_('COM_MESSAGES_INVALID_REPLY_ID')); + $this->setRedirect('index.php?option=com_messages&view=messages'); + } + } +} diff --git a/administrator/components/com_messages/controllers/messages.php b/administrator/components/com_messages/controllers/messages.php new file mode 100644 index 0000000..eb5cc82 --- /dev/null +++ b/administrator/components/com_messages/controllers/messages.php @@ -0,0 +1,37 @@ + true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } +} diff --git a/administrator/components/com_messages/helpers/html/index.html b/administrator/components/com_messages/helpers/html/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/helpers/html/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/helpers/html/messages.php b/administrator/components/com_messages/helpers/html/messages.php new file mode 100644 index 0000000..eda7e93 --- /dev/null +++ b/administrator/components/com_messages/helpers/html/messages.php @@ -0,0 +1,41 @@ + array('trash.png', 'messages.unpublish', 'JTRASHED', 'COM_MESSAGES_MARK_AS_UNREAD'), + 1 => array('tick.png', 'messages.unpublish', 'COM_MESSAGES_OPTION_READ', 'COM_MESSAGES_MARK_AS_UNREAD'), + 0 => array('publish_x.png', 'messages.publish', 'COM_MESSAGES_OPTION_UNREAD', 'COM_MESSAGES_MARK_AS_READ') + ); + $state = JArrayHelper::getValue($states, (int) $value, $states[0]); + $html = JHtml::_('image', 'admin/'.$state[0], JText::_($state[2]), null, true); + if ($canChange) + { + $html = '' + .$html.''; + } + + return $html; + } +} diff --git a/administrator/components/com_messages/helpers/index.html b/administrator/components/com_messages/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/helpers/messages.php b/administrator/components/com_messages/helpers/messages.php new file mode 100644 index 0000000..5a18f37 --- /dev/null +++ b/administrator/components/com_messages/helpers/messages.php @@ -0,0 +1,76 @@ +set($action->name, $user->authorise($action->name, 'com_messages')); + } + + return $result; + } + + /** + * Get a list of filter options for the state of a module. + * + * @return array An array of JHtmlOption elements. + */ + public static function getStateOptions() + { + // Build the filter options. + $options = array(); + $options[] = JHtml::_('select.option', '1', JText::_('COM_MESSAGES_OPTION_READ')); + $options[] = JHtml::_('select.option', '0', JText::_('COM_MESSAGES_OPTION_UNREAD')); + $options[] = JHtml::_('select.option', '-2', JText::_('JTRASHED')); + return $options; + } +} diff --git a/administrator/components/com_messages/index.html b/administrator/components/com_messages/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/messages.php b/administrator/components/com_messages/messages.php new file mode 100644 index 0000000..559d7b0 --- /dev/null +++ b/administrator/components/com_messages/messages.php @@ -0,0 +1,21 @@ +authorise('core.manage', 'com_messages')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$task = JFactory::getApplication()->input->get('task'); + +$controller = JControllerLegacy::getInstance('Messages'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_messages/messages.xml b/administrator/components/com_messages/messages.xml new file mode 100644 index 0000000..3ff9667 --- /dev/null +++ b/administrator/components/com_messages/messages.xml @@ -0,0 +1,32 @@ + + + com_messages + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_MESSAGES_XML_DESCRIPTION + + language/en-GB.com_messages.ini + + + + config.xml + controller.php + index.html + messages.php + controllers + helpers + models + tables + views + + + language/en-GB.com_messages.ini + language/en-GB.com_messages.sys.ini + + + diff --git a/administrator/components/com_messages/models/config.php b/administrator/components/com_messages/models/config.php new file mode 100644 index 0000000..5f0a42a --- /dev/null +++ b/administrator/components/com_messages/models/config.php @@ -0,0 +1,157 @@ +setState('user.id', $user->get('id')); + + // Load the parameters. + $params = JComponentHelper::getParams('com_messages'); + $this->setState('params', $params); + } + + /** + * Method to get a single record. + * + * @param integer The id of the primary key. + * + * @return mixed Object on success, false on failure. + */ + public function &getItem() + { + $item = new JObject; + + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->select('cfg_name, cfg_value') + ->from('#__messages_cfg') + ->where('user_id = '.(int) $this->getState('user.id')); + + $db->setQuery($query); + + try + { + $rows = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + foreach ($rows as $row) + { + $item->set($row->cfg_name, $row->cfg_value); + } + + $this->preprocessData('com_messages.config', $item); + + return $item; + } + + /** + * Method to get the record form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * @return JForm A JForm object on success, false on failure + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + // Get the form. + $form = $this->loadForm('com_messages.config', 'config', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + return $form; + } + + /** + * Method to save the form data. + * + * @param array The form data. + * @return boolean True on success. + */ + public function save($data) + { + $db = $this->getDbo(); + + if ($userId = (int) $this->getState('user.id')) + { + $db->setQuery( + 'DELETE FROM #__messages_cfg'. + ' WHERE user_id = '. $userId + ); + + try + { + $db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + $tuples = array(); + foreach ($data as $k => $v) + { + $tuples[] = '(' . $userId.', ' . $db->quote($k) . ', ' . $db->quote($v) . ')'; + } + + if ($tuples) + { + $db->setQuery( + 'INSERT INTO #__messages_cfg'. + ' (user_id, cfg_name, cfg_value)'. + ' VALUES '.implode(',', $tuples) + ); + + try + { + $db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + } + return true; + } + else + { + $this->setError('COM_MESSAGES_ERR_INVALID_USER'); + return false; + } + } +} diff --git a/administrator/components/com_messages/models/fields/index.html b/administrator/components/com_messages/models/fields/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/models/fields/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/models/fields/usermessages.php b/administrator/components/com_messages/models/fields/usermessages.php new file mode 100644 index 0000000..5792dcd --- /dev/null +++ b/administrator/components/com_messages/models/fields/usermessages.php @@ -0,0 +1,86 @@ +getQuery(true) + ->select('id') + ->from('#__usergroups'); + $db->setQuery($query); + + try + { + $groups = $db->loadColumn(); + } + catch (RuntimeException $e) + { + JError::raiseNotice(500, $e->getMessage()); + return null; + } + + foreach ($groups as $i => $group) + { + if (JAccess::checkGroup($group, 'core.admin')) + { + continue; + } + if (!JAccess::checkGroup($group, 'core.manage', 'com_messages')) + { + unset($groups[$i]); + continue; + } + if (!JAccess::checkGroup($group, 'core.login.admin')) + { + unset($groups[$i]); + continue; + } + } + return array_values($groups); + } + + /** + * Method to get the users to exclude from the list of users + * + * @return array|null array of users to exclude or null to to not exclude them + * @since 1.6 + */ + protected function getExcluded() + { + return array(JFactory::getUser()->id); + } +} diff --git a/administrator/components/com_messages/models/forms/config.xml b/administrator/components/com_messages/models/forms/config.xml new file mode 100644 index 0000000..939f7e9 --- /dev/null +++ b/administrator/components/com_messages/models/forms/config.xml @@ -0,0 +1,39 @@ + +
    +
    + + + + + + + + + + + +
    +
    diff --git a/administrator/components/com_messages/models/forms/index.html b/administrator/components/com_messages/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/models/forms/message.xml b/administrator/components/com_messages/models/forms/message.xml new file mode 100644 index 0000000..c4a9b41 --- /dev/null +++ b/administrator/components/com_messages/models/forms/message.xml @@ -0,0 +1,30 @@ + +
    +
    + + + + + +
    +
    diff --git a/administrator/components/com_messages/models/index.html b/administrator/components/com_messages/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/models/message.php b/administrator/components/com_messages/models/message.php new file mode 100644 index 0000000..b594e1d --- /dev/null +++ b/administrator/components/com_messages/models/message.php @@ -0,0 +1,325 @@ +input; + + $user = JFactory::getUser(); + $this->setState('user.id', $user->get('id')); + + $messageId = (int) $input->getInt('message_id'); + $this->setState('message.id', $messageId); + + $replyId = (int) $input->getInt('reply_id'); + $this->setState('reply.id', $replyId); + } + + /** + * Check that recipient user is the one trying to delete and then call parent delete method + * + * @param array &$pks An array of record primary keys. + * + * @return boolean True if successful, false if an error occurs. + * + * @since 3.1 + */ + public function delete(&$pks) + { + $pks = (array) $pks; + $table = $this->getTable(); + $user = JFactory::getUser(); + + // Iterate the items to delete each one. + foreach ($pks as $i => $pk) + { + if ($table->load($pk)) + { + if ($table->user_id_to !== $user->id) + { + // Prune items that you can't change. + unset($pks[$i]); + JLog::add(JText::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'), JLog::WARNING, 'jerror'); + return false; + } + } + else + { + $this->setError($table->getError()); + return false; + } + } + return parent::delete($pks); + } + + /** + * Returns a Table object, always creating it. + * + * @param type The table type to instantiate + * @param string A prefix for the table class name. Optional. + * @param array Configuration array for model. Optional. + * @return JTable A database object + * @since 1.6 + */ + public function getTable($type = 'Message', $prefix = 'MessagesTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Method to get a single record. + * + * @param integer The id of the primary key. + * @return mixed Object on success, false on failure. + * @since 1.6 + */ + public function getItem($pk = null) + { + if (!isset($this->item)) + { + if ($this->item = parent::getItem($pk)) + { + // Prime required properties. + if (empty($this->item->message_id)) + { + // Prepare data for a new record. + if ($replyId = $this->getState('reply.id')) + { + // If replying to a message, preload some data. + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->select('subject, user_id_from') + ->from('#__messages') + ->where('message_id = '.(int) $replyId); + + try + { + $message = $db->setQuery($query)->loadObject(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + $this->item->set('user_id_to', $message->user_id_from); + $re = JText::_('COM_MESSAGES_RE'); + if (stripos($message->subject, $re) !== 0) + { + $this->item->set('subject', $re.$message->subject); + } + } + } + elseif ($this->item->user_id_to != JFactory::getUser()->id) + { + $this->setError(JText::_('JERROR_ALERTNOAUTHOR')); + return false; + } + else { + // Mark message read + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->update('#__messages') + ->set('state = 1') + ->where('message_id = '.$this->item->message_id); + $db->setQuery($query)->execute(); + } + } + + // Get the user name for an existing messasge. + if ($this->item->user_id_from && $fromUser = new JUser($this->item->user_id_from)) + { + $this->item->set('from_user_name', $fromUser->name); + } + } + return $this->item; + } + + /** + * Method to get the record form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * @return JForm A JForm object on success, false on failure + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + // Get the form. + $form = $this->loadForm('com_messages.message', 'message', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_messages.edit.message.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + } + + $this->preprocessData('com_messages.message', $data); + + return $data; + } + + /** + * Checks that the current user matches the message recipient and calls the parent publish method + * + * @param array &$pks A list of the primary keys to change. + * @param integer $value The value of the published state. + * + * @return boolean True on success. + * + * @since 3.1 + */ + public function publish(&$pks, $value = 1) + { + $user = JFactory::getUser(); + $table = $this->getTable(); + $pks = (array) $pks; + + // Check that the recipient matches the current user + foreach ($pks as $i => $pk) + { + $table->reset(); + + if ($table->load($pk)) + { + if ($table->user_id_to !== $user->id) + { + // Prune items that you can't change. + unset($pks[$i]); + JLog::add(JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'), JLog::WARNING, 'jerror'); + return false; + } + } + + } + + return parent::publish($pks, $value); + } + + /** + * Method to save the form data. + * + * @param array The form data. + * + * @return boolean True on success. + */ + public function save($data) + { + $table = $this->getTable(); + + // Bind the data. + if (!$table->bind($data)) + { + $this->setError($table->getError()); + return false; + } + + // Assign empty values. + if (empty($table->user_id_from)) + { + $table->user_id_from = JFactory::getUser()->get('id'); + } + if ((int) $table->date_time == 0) + { + $table->date_time = JFactory::getDate()->toSql(); + } + + // Check the data. + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // Load the recipient user configuration. + $model = JModelLegacy::getInstance('Config', 'MessagesModel', array('ignore_request' => true)); + $model->setState('user.id', $table->user_id_to); + $config = $model->getItem(); + if (empty($config)) + { + $this->setError($model->getError()); + return false; + } + + if ($config->get('locked', false)) + { + $this->setError(JText::_('COM_MESSAGES_ERR_SEND_FAILED')); + return false; + } + + // Store the data. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + if ($config->get('mail_on_new', true)) + { + // Load the user details (already valid from table check). + $fromUser = JUser::getInstance($table->user_id_from); + $toUser = JUser::getInstance($table->user_id_to); + $debug = JFactory::getConfig()->get('debug_lang'); + $default_language = JComponentHelper::getParams('com_languages')->get('administrator'); + $lang = JLanguage::getInstance($toUser->getParam('admin_language', $default_language), $debug); + $lang->load('com_messages', JPATH_ADMINISTRATOR); + + $siteURL = JUri::root() . 'administrator/index.php?option=com_messages&view=message&message_id='.$table->message_id; + $sitename = JFactory::getApplication()->getCfg('sitename'); + + $subject = sprintf($lang->_('COM_MESSAGES_NEW_MESSAGE_ARRIVED'), $sitename); + $msg = sprintf($lang->_('COM_MESSAGES_PLEASE_LOGIN'), $siteURL); + JFactory::getMailer()->sendMail($fromUser->email, $fromUser->name, $toUser->email, $subject, $msg); + } + + return true; + } +} diff --git a/administrator/components/com_messages/models/messages.php b/administrator/components/com_messages/models/messages.php new file mode 100644 index 0000000..551e02a --- /dev/null +++ b/administrator/components/com_messages/models/messages.php @@ -0,0 +1,138 @@ +getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $state = $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string'); + $this->setState('filter.state', $state); + + // List state information. + parent::populateState('a.date_time', 'desc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string A prefix for the store id. + * + * @return string A store id. + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.state'); + + return parent::getStoreId($id); + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + $user = JFactory::getUser(); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.*, ' . + 'u.name AS user_from' + ) + ); + $query->from('#__messages AS a'); + + // Join over the users for message owner. + $query->join('INNER', '#__users AS u ON u.id = a.user_id_from') + ->where('a.user_id_to = ' . (int) $user->get('id')); + + // Filter by published state. + $state = $this->getState('filter.state'); + if (is_numeric($state)) + { + $query->where('a.state = ' . (int) $state); + } + elseif ($state === '') + { + $query->where('(a.state IN (0, 1))'); + } + + // Filter by search in subject or message. + $search = $this->getState('filter.search'); + + if (!empty($search)) + { + $search = $db->quote('%' . $db->escape($search, true) . '%', false); + $query->where('a.subject LIKE ' . $search . ' OR a.message LIKE ' . $search); + } + + // Add the list ordering clause. + $query->order($db->escape($this->getState('list.ordering', 'a.date_time')) . ' ' . $db->escape($this->getState('list.direction', 'DESC'))); + + //echo nl2br(str_replace('#__','jos_',$query)); + return $query; + } +} diff --git a/administrator/components/com_messages/tables/index.html b/administrator/components/com_messages/tables/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/tables/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/tables/message.php b/administrator/components/com_messages/tables/message.php new file mode 100644 index 0000000..628410c --- /dev/null +++ b/administrator/components/com_messages/tables/message.php @@ -0,0 +1,131 @@ +user_id_from); + if (empty($user->id)) + { + $this->setError(JText::_('COM_MESSAGES_ERROR_INVALID_FROM_USER')); + return false; + } + + $user = new JUser($this->user_id_to); + if (empty($user->id)) + { + $this->setError(JText::_('COM_MESSAGES_ERROR_INVALID_TO_USER')); + return false; + } + + if (empty($this->subject)) + { + $this->setError(JText::_('COM_MESSAGES_ERROR_INVALID_SUBJECT')); + return false; + } + + if (empty($this->message)) + { + $this->setError(JText::_('COM_MESSAGES_ERROR_INVALID_MESSAGE')); + return false; + } + + return true; + } + + /** + * Method to set the publishing state for a row or list of rows in the database + * table. The method respects checked out rows by other users and will attempt + * to checkin rows that it can after adjustments are made. + * + * @param mixed An optional array of primary key values to update. If not + * set the instance property value is used. + * @param integer The publishing state. eg. [0 = unpublished, 1 = published] + * @param integer The user id of the user performing the operation. + * @return boolean True on success. + * @since 1.6 + */ + public function publish($pks = null, $state = 1, $userId = 0) + { + $k = $this->_tbl_key; + + // Sanitize input. + JArrayHelper::toInteger($pks); + $state = (int) $state; + + // If there are no primary keys set check to see if the instance key is set. + if (empty($pks)) + { + if ($this->$k) + { + $pks = array($this->$k); + } + // Nothing to set publishing state on, return false. + else { + $this->setError(JText::_('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED')); + return false; + } + } + + // Build the WHERE clause for the primary keys. + $where = $k.' IN ('.implode(',', $pks).')'; + + // Update the publishing state for rows with the given primary keys. + $this->_db->setQuery( + 'UPDATE '.$this->_db->quoteName($this->_tbl). + ' SET '.$this->_db->quoteName('state').' = '.(int) $state . + ' WHERE ('.$where.')' + ); + + try + { + $this->_db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + // If the JTable instance value is in the list of primary keys that were set, set the instance. + if (in_array($this->$k, $pks)) + { + $this->state = $state; + } + + $this->setError(''); + return true; + } +} diff --git a/administrator/components/com_messages/views/config/index.html b/administrator/components/com_messages/views/config/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/views/config/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/views/config/tmpl/default.php b/administrator/components/com_messages/views/config/tmpl/default.php new file mode 100644 index 0000000..6432ec7 --- /dev/null +++ b/administrator/components/com_messages/views/config/tmpl/default.php @@ -0,0 +1,71 @@ + + +
    +
    +
    + + +
    +
    + + + +
    diff --git a/administrator/components/com_messages/views/config/tmpl/index.html b/administrator/components/com_messages/views/config/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/views/config/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/views/config/view.html.php b/administrator/components/com_messages/views/config/view.html.php new file mode 100644 index 0000000..8a77dda --- /dev/null +++ b/administrator/components/com_messages/views/config/view.html.php @@ -0,0 +1,48 @@ +form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + // Bind the record to the form. + $this->form->bind($this->item); + + parent::display($tpl); + } +} diff --git a/administrator/components/com_messages/views/index.html b/administrator/components/com_messages/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/views/message/index.html b/administrator/components/com_messages/views/message/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/views/message/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/views/message/tmpl/default.php b/administrator/components/com_messages/views/message/tmpl/default.php new file mode 100644 index 0000000..3f2b458 --- /dev/null +++ b/administrator/components/com_messages/views/message/tmpl/default.php @@ -0,0 +1,52 @@ + +
    +
    +
    +
    + +
    +
    + item->get('from_user_name');?> +
    +
    +
    +
    + +
    +
    + item->date_time);?> +
    +
    +
    +
    + +
    +
    + item->subject;?> +
    +
    +
    +
    + +
    +
    + item->message; ?> +
    +
    + + + +
    +
    diff --git a/administrator/components/com_messages/views/message/tmpl/edit.php b/administrator/components/com_messages/views/message/tmpl/edit.php new file mode 100644 index 0000000..00d4224 --- /dev/null +++ b/administrator/components/com_messages/views/message/tmpl/edit.php @@ -0,0 +1,56 @@ + + +
    +
    +
    +
    + form->getLabel('user_id_to'); ?> +
    +
    + form->getInput('user_id_to'); ?> +
    +
    +
    +
    + form->getLabel('subject'); ?> +
    +
    + form->getInput('subject'); ?> +
    +
    +
    +
    + form->getLabel('message'); ?> +
    +
    + form->getInput('message'); ?> +
    +
    +
    + + +
    diff --git a/administrator/components/com_messages/views/message/tmpl/index.html b/administrator/components/com_messages/views/message/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/views/message/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/views/message/view.html.php b/administrator/components/com_messages/views/message/view.html.php new file mode 100644 index 0000000..10c9372 --- /dev/null +++ b/administrator/components/com_messages/views/message/view.html.php @@ -0,0 +1,70 @@ +form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + parent::display($tpl); + $this->addToolbar(); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + if ($this->getLayout() == 'edit') + { + JToolbarHelper::title(JText::_('COM_MESSAGES_WRITE_PRIVATE_MESSAGE'), 'new-privatemessage.png'); + JToolbarHelper::save('message.save', 'COM_MESSAGES_TOOLBAR_SEND'); + JToolbarHelper::cancel('message.cancel'); + JToolbarHelper::help('JHELP_COMPONENTS_MESSAGING_WRITE'); + } + else + { + JToolbarHelper::title(JText::_('COM_MESSAGES_VIEW_PRIVATE_MESSAGE'), 'inbox.png'); + $sender = JUser::getInstance($this->item->user_id_from); + if ($sender->authorise('core.admin') || $sender->authorise('core.manage', 'com_messages') && $sender->authorise('core.login.admin')) + { + JToolbarHelper::custom('message.reply', 'redo', null, 'COM_MESSAGES_TOOLBAR_REPLY', false); + } + JToolbarHelper::cancel('message.cancel'); + JToolbarHelper::help('JHELP_COMPONENTS_MESSAGING_READ'); + } + } +} diff --git a/administrator/components/com_messages/views/messages/index.html b/administrator/components/com_messages/views/messages/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/views/messages/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/views/messages/tmpl/default.php b/administrator/components/com_messages/views/messages/tmpl/default.php new file mode 100644 index 0000000..5438d71 --- /dev/null +++ b/administrator/components/com_messages/views/messages/tmpl/default.php @@ -0,0 +1,110 @@ +escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +?> + +
    +sidebar)) : ?> +
    + sidebar; ?> +
    +
    + +
    + +
    + +
    + + +
    +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + items as $i => $item) : + $canChange = $user->authorise('core.edit.state', 'com_messages'); + ?> + + + + + + + + + +
    + + + + + + + + + +
    + pagination->getListFooter(); ?> +
    + message_id); ?> + + + escape($item->subject); ?> + + state, $i, $canChange); ?> + + user_from; ?> + + date_time, JText::_('DATE_FORMAT_LC2')); ?> +
    + +
    + + + + + +
    +
    + diff --git a/administrator/components/com_messages/views/messages/tmpl/index.html b/administrator/components/com_messages/views/messages/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_messages/views/messages/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_messages/views/messages/view.html.php b/administrator/components/com_messages/views/messages/view.html.php new file mode 100644 index 0000000..1bf6c58 --- /dev/null +++ b/administrator/components/com_messages/views/messages/view.html.php @@ -0,0 +1,101 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + $state = $this->get('State'); + $canDo = MessagesHelper::getActions(); + + JToolbarHelper::title(JText::_('COM_MESSAGES_MANAGER_MESSAGES'), 'inbox.png'); + + if ($canDo->get('core.create')) + { + JToolbarHelper::addNew('message.add'); + } + + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::divider(); + JToolbarHelper::publish('messages.publish', 'COM_MESSAGES_TOOLBAR_MARK_AS_READ'); + JToolbarHelper::unpublish('messages.unpublish', 'COM_MESSAGES_TOOLBAR_MARK_AS_UNREAD'); + } + + if ($state->get('filter.state') == -2 && $canDo->get('core.delete')) + { + JToolbarHelper::divider(); + JToolbarHelper::deleteList('', 'messages.delete', 'JTOOLBAR_EMPTY_TRASH'); + } elseif ($canDo->get('core.edit.state')) + { + JToolbarHelper::divider(); + JToolbarHelper::trash('messages.trash'); + } + + //JToolbarHelper::addNew('module.add'); + JToolbarHelper::divider(); + $bar = JToolBar::getInstance('toolbar'); + JHtml::_('bootstrap.modal', 'collapseModal'); + $title = JText::_('COM_MESSAGES_TOOLBAR_MY_SETTINGS'); + $dhtml = " + $title"; + $bar->appendButton('Custom', $dhtml, 'config'); + + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_messages'); + } + + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_COMPONENTS_MESSAGING_INBOX'); + } +} diff --git a/administrator/components/com_modules/access.xml b/administrator/components/com_modules/access.xml new file mode 100644 index 0000000..f4d8172 --- /dev/null +++ b/administrator/components/com_modules/access.xml @@ -0,0 +1,11 @@ + + +
    + + + + + + +
    +
    diff --git a/administrator/components/com_modules/config.xml b/administrator/components/com_modules/config.xml new file mode 100644 index 0000000..412d3af --- /dev/null +++ b/administrator/components/com_modules/config.xml @@ -0,0 +1,18 @@ + + +
    + + +
    +
    diff --git a/administrator/components/com_modules/controller.php b/administrator/components/com_modules/controller.php new file mode 100644 index 0000000..d00fa14 --- /dev/null +++ b/administrator/components/com_modules/controller.php @@ -0,0 +1,54 @@ +input->get('view', 'modules')); + + $view = $this->input->get('view', 'modules'); + $layout = $this->input->get('layout', 'default'); + $id = $this->input->getInt('id'); + + // Check for edit form. + if ($view == 'module' && $layout == 'edit' && !$this->checkEditId('com_modules.edit.module', $id)) + { + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_modules&view=modules', false)); + + return false; + } + + parent::display(); + } +} diff --git a/administrator/components/com_modules/controllers/index.html b/administrator/components/com_modules/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/controllers/module.php b/administrator/components/com_modules/controllers/module.php new file mode 100644 index 0000000..e3028c5 --- /dev/null +++ b/administrator/components/com_modules/controllers/module.php @@ -0,0 +1,152 @@ +input->get('eid', 0, 'int'); + if (empty($extensionId)) + { + $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_item.'&layout=edit', false)); + return JError::raiseWarning(500, JText::_('COM_MODULES_ERROR_INVALID_EXTENSION')); + } + + $app->setUserState('com_modules.add.module.extension_id', $extensionId); + $app->setUserState('com_modules.add.module.params', null); + + // Parameters could be coming in for a new item, so let's set them. + $params = $app->input->get('params', array(), 'array'); + $app->setUserState('com_modules.add.module.params', $params); + } + + /** + * Override parent cancel method to reset the add module state. + * + * @param string $key The name of the primary key of the URL variable. + * + * @return boolean True if access level checks pass, false otherwise. + * + * @since 1.6 + */ + public function cancel($key = null) + { + $app = JFactory::getApplication(); + + $result = parent::cancel(); + + $app->setUserState('com_modules.add.module.extension_id', null); + $app->setUserState('com_modules.add.module.params', null); + + return $result; + } + + /** + * Override parent allowSave method. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowSave($data, $key = 'id') + { + // use custom position if selected + if (isset($data['custom_position'])) + { + if (empty($data['position'])) + { + $data['position'] = $data['custom_position']; + } + + unset($data['custom_position']); + } + + return parent::allowSave($data, $key); + } + + /** + * Method to run batch operations. + * + * @param string $model The model + * + * @return boolean True on success. + * + * @since 1.7 + */ + public function batch($model = null) + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Set the model + $model = $this->getModel('Module', '', array()); + + // Preset the redirect + $this->setRedirect(JRoute::_('index.php?option=com_modules&view=modules'.$this->getRedirectToListAppend(), false)); + + return parent::batch($model); + } + + /** + * Function that allows child controller access to model data after the data has been saved. + * + * @param JModelLegacy $model The data model object. + * @param array $validData The validated data. + * + * @return void + * + * @since 1.6 + */ + protected function postSaveHook(JModelLegacy $model, $validData = array()) + { + $app = JFactory::getApplication(); + $task = $this->getTask(); + + switch ($task) + { + case 'save2new': + $app->setUserState('com_modules.add.module.extension_id', $model->getState('module.extension_id')); + break; + + default: + $app->setUserState('com_modules.add.module.extension_id', null); + break; + } + + $app->setUserState('com_modules.add.module.params', null); + } +} diff --git a/administrator/components/com_modules/controllers/modules.php b/administrator/components/com_modules/controllers/modules.php new file mode 100644 index 0000000..edbdeaf --- /dev/null +++ b/administrator/components/com_modules/controllers/modules.php @@ -0,0 +1,65 @@ +input->post->get('cid', array(), 'array'); + JArrayHelper::toInteger($pks); + + try { + if (empty($pks)) + { + throw new Exception(JText::_('COM_MODULES_ERROR_NO_MODULES_SELECTED')); + } + $model = $this->getModel(); + $model->duplicate($pks); + $this->setMessage(JText::plural('COM_MODULES_N_MODULES_DUPLICATED', count($pks))); + } catch (Exception $e) + { + JError::raiseWarning(500, $e->getMessage()); + } + + $this->setRedirect('index.php?option=com_modules&view=modules'); + } + + /** + * Method to get a model object, loading it if required. + * + * @param string $name The model name. Optional. + * @param string $prefix The class prefix. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return object The model. + * + * @since 1.6 + */ + public function getModel($name = 'Module', $prefix = 'ModulesModel', $config = array('ignore_request' => true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } +} diff --git a/administrator/components/com_modules/helpers/html/index.html b/administrator/components/com_modules/helpers/html/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/helpers/html/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/helpers/html/modules.php b/administrator/components/com_modules/helpers/html/modules.php new file mode 100644 index 0000000..7b69eda --- /dev/null +++ b/administrator/components/com_modules/helpers/html/modules.php @@ -0,0 +1,229 @@ +element, $template->name); + } + + return $options; + } + + /** + * Builds an array of template type options + * + * @return array + */ + public static function types() + { + $options = array(); + $options[] = JHtml::_('select.option', 'user', 'COM_MODULES_OPTION_POSITION_USER_DEFINED'); + $options[] = JHtml::_('select.option', 'template', 'COM_MODULES_OPTION_POSITION_TEMPLATE_DEFINED'); + + return $options; + } + + /** + * Builds an array of template state options + * + * @return array + */ + public static function templateStates() + { + $options = array(); + $options[] = JHtml::_('select.option', '1', 'JENABLED'); + $options[] = JHtml::_('select.option', '0', 'JDISABLED'); + + return $options; + } + + /** + * Returns a published state on a grid + * + * @param integer $value The state value. + * @param integer $i The row index + * @param boolean $enabled An optional setting for access control on the action. + * @param string $checkbox An optional prefix for checkboxes. + * + * @return string The Html code + * + * @see JHtmlJGrid::state + * @since 1.7.1 + */ + public static function state($value, $i, $enabled = true, $checkbox = 'cb') + { + $states = array( + 1 => array( + 'unpublish', + 'COM_MODULES_EXTENSION_PUBLISHED_ENABLED', + 'COM_MODULES_HTML_UNPUBLISH_ENABLED', + 'COM_MODULES_EXTENSION_PUBLISHED_ENABLED', + true, + 'publish', + 'publish' + ), + 0 => array( + 'publish', + 'COM_MODULES_EXTENSION_UNPUBLISHED_ENABLED', + 'COM_MODULES_HTML_PUBLISH_ENABLED', + 'COM_MODULES_EXTENSION_UNPUBLISHED_ENABLED', + true, + 'unpublish', + 'unpublish' + ), + -1 => array( + 'unpublish', + 'COM_MODULES_EXTENSION_PUBLISHED_DISABLED', + 'COM_MODULES_HTML_UNPUBLISH_DISABLED', + 'COM_MODULES_EXTENSION_PUBLISHED_DISABLED', + true, + 'warning', + 'warning' + ), + -2 => array( + 'publish', + 'COM_MODULES_EXTENSION_UNPUBLISHED_DISABLED', + 'COM_MODULES_HTML_PUBLISH_DISABLED', + 'COM_MODULES_EXTENSION_UNPUBLISHED_DISABLED', + true, + 'unpublish', + 'unpublish' + ), + ); + + return JHtml::_('jgrid.state', $states, $value, $i, 'modules.', $enabled, true, $checkbox); + } + + /** + * Display a batch widget for the module position selector. + * + * @param integer $clientId The client ID + * + * @return string The necessary positions for the widget. + * + * @since 2.5 + */ + + public static function positions($clientId, $state = 1, $selectedPosition = '') + { + require_once JPATH_ADMINISTRATOR . '/components/com_templates/helpers/templates.php'; + $templates = array_keys(ModulesHelper::getTemplates($clientId, $state)); + $templateGroups = array(); + + // Add an empty value to be able to deselect a module position + $option = ModulesHelper::createOption(); + $templateGroups[''] = ModulesHelper::createOptionGroup('', array($option)); + + // Add positions from templates + $isTemplatePosition = false; + foreach ($templates as $template) + { + $options = array(); + + $positions = TemplatesHelper::getPositions($clientId, $template); + if (is_array($positions)) foreach ($positions as $position) + { + $text = ModulesHelper::getTranslatedModulePosition($clientId, $template, $position) . ' [' . $position . ']'; + $options[] = ModulesHelper::createOption($position, $text); + + if (!$isTemplatePosition && $selectedPosition === $position) + { + $isTemplatePosition = true; + } + } + + $templateGroups[$template] = ModulesHelper::createOptionGroup(ucfirst($template), $options); + } + + // Add custom position to options + $customGroupText = JText::_('COM_MODULES_CUSTOM_POSITION'); + + $editPositions = true; + $customPositions = ModulesHelper::getPositions($clientId, $editPositions); + $templateGroups[$customGroupText] = ModulesHelper::createOptionGroup($customGroupText, $customPositions); + + return $templateGroups; + } + + public static function batchOptions() + { + // Create the copy/move options. + $options = array( + JHtml::_('select.option', 'c', JText::_('JLIB_HTML_BATCH_COPY')), + JHtml::_('select.option', 'm', JText::_('JLIB_HTML_BATCH_MOVE')) + ); + + echo JHtml::_('select.radiolist', $options, 'batch[move_copy]', '', 'value', 'text', 'm'); + } + + /** + * Method to get the field options. + * + * @param integer $clientId The client ID + * + * @return array The field option objects. + * + * @since 2.5 + */ + public static function positionList($clientId = 0) + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('DISTINCT(position) as value') + ->select('position as text') + ->from($db->quoteName('#__modules')) + ->where($db->quoteName('client_id') . ' = ' . (int) $clientId) + ->order('position'); + + // Get the options. + $db->setQuery($query); + + try + { + $options = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + } + + // Pop the first item off the array if it's blank + if (count($options)) + { + if (strlen($options[0]->text) < 1) + { + array_shift($options); + } + } + + return $options; + } +} diff --git a/administrator/components/com_modules/helpers/index.html b/administrator/components/com_modules/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/helpers/modules.php b/administrator/components/com_modules/helpers/modules.php new file mode 100644 index 0000000..bf5fa39 --- /dev/null +++ b/administrator/components/com_modules/helpers/modules.php @@ -0,0 +1,324 @@ +set($action->name, $user->authorise($action->name, 'com_modules')); + } + + return $result; + } + + /** + * Get a list of filter options for the state of a module. + * + * @return array An array of JHtmlOption elements. + */ + public static function getStateOptions() + { + // Build the filter options. + $options = array(); + $options[] = JHtml::_('select.option', '1', JText::_('JPUBLISHED')); + $options[] = JHtml::_('select.option', '0', JText::_('JUNPUBLISHED')); + $options[] = JHtml::_('select.option', '-2', JText::_('JTRASHED')); + return $options; + } + + /** + * Get a list of filter options for the application clients. + * + * @return array An array of JHtmlOption elements. + */ + public static function getClientOptions() + { + // Build the filter options. + $options = array(); + $options[] = JHtml::_('select.option', '0', JText::_('JSITE')); + $options[] = JHtml::_('select.option', '1', JText::_('JADMINISTRATOR')); + return $options; + } + + /** + * Get a list of modules positions + * + * @param integer $clientId Client ID + * + * @return array A list of positions + */ + public static function getPositions($clientId, $editPositions = false) + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('DISTINCT(position)') + ->from('#__modules') + ->where($db->quoteName('client_id') . ' = ' . (int) $clientId) + ->order('position'); + + $db->setQuery($query); + + try + { + $positions = $db->loadColumn(); + $positions = is_array($positions) ? $positions : array(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + return; + } + + // Build the list + $options = array(); + foreach ($positions as $position) + { + if (!$position && !$editPositions) + { + $options[] = JHtml::_('select.option', 'none', ':: ' . JText::_('JNONE') . ' ::'); + + } + else + { + $options[] = JHtml::_('select.option', $position, $position); + } + } + return $options; + } + + /** + * Return a list of templates + * + * @param integer $clientId Client ID + * @param string $state State + * @param string $template Template name + * + * @return array List of templates + */ + public static function getTemplates($clientId = 0, $state = '', $template = '') + { + $db = JFactory::getDbo(); + + // Get the database object and a new query object. + $query = $db->getQuery(true); + + // Build the query. + $query->select('element, name, enabled') + ->from('#__extensions') + ->where('client_id = ' . (int) $clientId) + ->where('type = ' . $db->quote('template')); + if ($state != '') + { + $query->where('enabled = ' . $db->quote($state)); + } + + if ($template != '') + { + $query->where('element = ' . $db->quote($template)); + } + + // Set the query and load the templates. + $db->setQuery($query); + $templates = $db->loadObjectList('element'); + return $templates; + } + + /** + * Get a list of the unique modules installed in the client application. + * + * @param int $clientId The client id. + * + * @return array Array of unique modules + */ + public static function getModules($clientId) + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('element AS value, name AS text') + ->from('#__extensions as e') + ->where('e.client_id = ' . (int) $clientId) + ->where('type = ' . $db->quote('module')) + ->join('LEFT', '#__modules as m ON m.module=e.element AND m.client_id=e.client_id') + ->where('m.module IS NOT NULL') + ->group('element,name'); + + $db->setQuery($query); + $modules = $db->loadObjectList(); + $lang = JFactory::getLanguage(); + + foreach ($modules as $i => $module) + { + $extension = $module->value; + $path = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE; + $source = $path . "/modules/$extension"; + $lang->load("$extension.sys", $path, null, false, false) + || $lang->load("$extension.sys", $source, null, false, false) + || $lang->load("$extension.sys", $path, $lang->getDefault(), false, false) + || $lang->load("$extension.sys", $source, $lang->getDefault(), false, false); + $modules[$i]->text = JText::_($module->text); + } + JArrayHelper::sortObjects($modules, 'text', 1, true, true); + return $modules; + } + + /** + * Get a list of the assignment options for modules to menus. + * + * @param int $clientId The client id. + * + * @return array + */ + public static function getAssignmentOptions($clientId) + { + $options = array(); + $options[] = JHtml::_('select.option', '0', 'COM_MODULES_OPTION_MENU_ALL'); + $options[] = JHtml::_('select.option', '-', 'COM_MODULES_OPTION_MENU_NONE'); + + if ($clientId == 0) + { + $options[] = JHtml::_('select.option', '1', 'COM_MODULES_OPTION_MENU_INCLUDE'); + $options[] = JHtml::_('select.option', '-1', 'COM_MODULES_OPTION_MENU_EXCLUDE'); + } + + return $options; + } + + /** + * Return a translated module position name + * + * @param string $template Template name + * @param string $position Position name + * + * @return string Return a translated position name + * + * @since 3.0 + */ + public static function getTranslatedModulePosition($clientId, $template, $position) + { + // Template translation + $lang = JFactory::getLanguage(); + $path = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE; + + $lang->load('tpl_'.$template.'.sys', $path, null, false, false) + || $lang->load('tpl_'.$template.'.sys', $path.'/templates/'.$template, null, false, false) + || $lang->load('tpl_'.$template.'.sys', $path, $lang->getDefault(), false, false) + || $lang->load('tpl_'.$template.'.sys', $path.'/templates/'.$template, $lang->getDefault(), false, false); + + $langKey = strtoupper('TPL_' . $template . '_POSITION_' . $position); + $text = JText::_($langKey); + + // Avoid untranslated strings + if (!self::isTranslatedText($langKey, $text)) + { + // Modules component translation + $langKey = strtoupper('COM_MODULES_POSITION_' . $position); + $text = JText::_($langKey); + + // Avoid untranslated strings + if (!self::isTranslatedText($langKey, $text)) + { + // Try to humanize the position name + $text = ucfirst(preg_replace('/^' . $template . '\-/', '', $position)); + $text = ucwords(str_replace(array('-', '_'), ' ', $text)); + } + } + + return $text; + } + + /** + * Check if the string was translated + * + * @param string $langKey Language file text key + * @param string $text The "translated" text to be checked + * + * @return boolean Return true for translated text + * + * @since 3.0 + */ + public static function isTranslatedText($langKey, $text) + { + return $text !== $langKey; + } + + /** + * Create and return a new Option + * + * @param string $value The option value [optional] + * @param string $text The option text [optional] + * + * @return object The option as an object (stdClass instance) + * + * @since 3.0 + */ + public static function createOption($value = '', $text = '') + { + if (empty($text)) + { + $text = $value; + } + + $option = new stdClass; + $option->value = $value; + $option->text = $text; + + return $option; + } + + /** + * Create and return a new Option Group + * + * @param string $label Value and label for group [optional] + * @param array $options Array of options to insert into group [optional] + * + * @return array Return the new group as an array + * + * @since 3.0 + */ + public static function createOptionGroup($label = '', $options = array()) + { + $group = array(); + $group['value'] = $label; + $group['text'] = $label; + $group['items'] = $options; + + return $group; + } +} diff --git a/administrator/components/com_modules/helpers/xml.php b/administrator/components/com_modules/helpers/xml.php new file mode 100644 index 0000000..e559026 --- /dev/null +++ b/administrator/components/com_modules/helpers/xml.php @@ -0,0 +1,46 @@ + $row) + { + if ($row->module == '') + { + $rows[$i]->name = 'custom'; + $rows[$i]->module = 'custom'; + $rows[$i]->descrip = 'Custom created module, using Module Manager New function'; + } + else + { + $data = JInstaller::parseXMLInstallFile($row->path . '/' . $row->file); + + if ($data['type'] == 'module') + { + $rows[$i]->name = $data['name']; + $rows[$i]->descrip = $data['description']; + } + } + } + } +} diff --git a/administrator/components/com_modules/index.html b/administrator/components/com_modules/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/models/forms/advanced.xml b/administrator/components/com_modules/models/forms/advanced.xml new file mode 100644 index 0000000..67cac97 --- /dev/null +++ b/administrator/components/com_modules/models/forms/advanced.xml @@ -0,0 +1,48 @@ + +
    + +
    + + + + + + + + + + +
    +
    +
    diff --git a/administrator/components/com_modules/models/forms/index.html b/administrator/components/com_modules/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/models/forms/module.xml b/administrator/components/com_modules/models/forms/module.xml new file mode 100644 index 0000000..d6b7f89 --- /dev/null +++ b/administrator/components/com_modules/models/forms/module.xml @@ -0,0 +1,119 @@ + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    diff --git a/administrator/components/com_modules/models/index.html b/administrator/components/com_modules/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/models/module.php b/administrator/components/com_modules/models/module.php new file mode 100644 index 0000000..9143f99 --- /dev/null +++ b/administrator/components/com_modules/models/module.php @@ -0,0 +1,1085 @@ +input->getInt('id'); + + if (!$pk) + { + if ($extensionId = (int) $app->getUserState('com_modules.add.module.extension_id')) + { + $this->setState('extension.id', $extensionId); + } + } + + $this->setState('module.id', $pk); + + // Load the parameters. + $params = JComponentHelper::getParams('com_modules'); + $this->setState('params', $params); + } + + /** + * Method to perform batch operations on a set of modules. + * + * @param array $commands An array of commands to perform. + * @param array $pks An array of item ids. + * @param array $contexts An array of item contexts. + * + * @return boolean Returns true on success, false on failure. + * + * @since 1.7 + */ + public function batch($commands, $pks, $contexts) + { + // Sanitize user ids. + $pks = array_unique($pks); + JArrayHelper::toInteger($pks); + + // Remove any values of zero. + if (array_search(0, $pks, true)) + { + unset($pks[array_search(0, $pks, true)]); + } + + if (empty($pks)) + { + $this->setError(JText::_('JGLOBAL_NO_ITEM_SELECTED')); + return false; + } + + $done = false; + + if (!empty($commands['position_id'])) + { + $cmd = JArrayHelper::getValue($commands, 'move_copy', 'c'); + + if (!empty($commands['position_id'])) + { + if ($cmd == 'c') + { + $result = $this->batchCopy($commands['position_id'], $pks, $contexts); + if (is_array($result)) + { + $pks = $result; + } + else + { + return false; + } + } + elseif ($cmd == 'm' && !$this->batchMove($commands['position_id'], $pks, $contexts)) + { + return false; + } + $done = true; + } + } + + if (!empty($commands['assetgroup_id'])) + { + if (!$this->batchAccess($commands['assetgroup_id'], $pks, $contexts)) + { + return false; + } + + $done = true; + } + + if (!empty($commands['language_id'])) + { + if (!$this->batchLanguage($commands['language_id'], $pks, $contexts)) + { + return false; + } + + $done = true; + } + + if (!$done) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_INSUFFICIENT_BATCH_INFORMATION')); + return false; + } + + // Clear the cache + $this->cleanCache(); + + return true; + } + + /** + * Batch copy modules to a new position or current. + * + * @param integer $value The new value matching a module position. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 2.5 + */ + protected function batchCopy($value, $pks, $contexts) + { + // Set the variables + $user = JFactory::getUser(); + $table = $this->getTable(); + $newIds = array(); + $i = 0; + + foreach ($pks as $pk) + { + if ($user->authorise('core.create', 'com_modules')) + { + $table->reset(); + $table->load($pk); + + // Set the new position + if ($value == 'noposition') + { + $position = ''; + } + elseif ($value == 'nochange') + { + $position = $table->position; + } + else + { + $position = $value; + } + $table->position = $position; + + // Alter the title if necessary + $data = $this->generateNewTitle(0, $table->title, $table->position); + $table->title = $data['0']; + + // Reset the ID because we are making a copy + $table->id = 0; + + // Unpublish the new module + $table->published = 0; + + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Get the new item ID + $newId = $table->get('id'); + + // Add the new ID to the array + $newIds[$i] = $newId; + $i++; + + // Now we need to handle the module assignments + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->select($db->quoteName('menuid')) + ->from($db->quoteName('#__modules_menu')) + ->where($db->quoteName('moduleid') . ' = ' . $pk); + $db->setQuery($query); + $menus = $db->loadColumn(); + + // Insert the new records into the table + foreach ($menus as $menu) + { + $query->clear() + ->insert($db->quoteName('#__modules_menu')) + ->columns(array($db->quoteName('moduleid'), $db->quoteName('menuid'))) + ->values($newId . ', ' . $menu); + $db->setQuery($query); + $db->execute(); + } + } + else + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE')); + return false; + } + } + + // Clean the cache + $this->cleanCache(); + + return $newIds; + } + + /** + * Batch move modules to a new position or current. + * + * @param integer $value The new value matching a module position. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 2.5 + */ + protected function batchMove($value, $pks, $contexts) + { + // Set the variables + $user = JFactory::getUser(); + $table = $this->getTable(); + + foreach ($pks as $pk) + { + if ($user->authorise('core.edit', 'com_modules')) + { + $table->reset(); + $table->load($pk); + + // Set the new position + if ($value == 'noposition') + { + $position = ''; + } + elseif ($value == 'nochange') + { + $position = $table->position; + } + else + { + $position = $value; + } + $table->position = $position; + + // Alter the title if necessary + $data = $this->generateNewTitle(0, $table->title, $table->position); + $table->title = $data['0']; + + // Unpublish the moved module + $table->published = 0; + + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + } + else + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT')); + return false; + } + } + + // Clean the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to delete rows. + * + * @param array &$pks An array of item ids. + * + * @return boolean Returns true on success, false on failure. + * + * @since 1.6 + * @throws Exception + */ + public function delete(&$pks) + { + $pks = (array) $pks; + $user = JFactory::getUser(); + $table = $this->getTable(); + + // Iterate the items to delete each one. + foreach ($pks as $pk) + { + if ($table->load($pk)) + { + // Access checks. + if (!$user->authorise('core.delete', 'com_modules') || $table->published != -2) + { + JError::raiseWarning(403, JText::_('JERROR_CORE_DELETE_NOT_PERMITTED')); + return; + } + + if (!$table->delete($pk)) + { + throw new Exception($table->getError()); + } + else + { + // Delete the menu assignments + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->delete('#__modules_menu') + ->where('moduleid=' . (int) $pk); + $db->setQuery($query); + $db->execute(); + } + + // Clear module cache + parent::cleanCache($table->module, $table->client_id); + } + else + { + throw new Exception($table->getError()); + } + } + + // Clear modules cache + $this->cleanCache(); + + return true; + } + + /** + * Method to duplicate modules. + * + * @param array &$pks An array of primary key IDs. + * + * @return boolean True if successful. + * + * @since 1.6 + * @throws Exception + */ + public function duplicate(&$pks) + { + $user = JFactory::getUser(); + $db = $this->getDbo(); + + // Access checks. + if (!$user->authorise('core.create', 'com_modules')) + { + throw new Exception(JText::_('JERROR_CORE_CREATE_NOT_PERMITTED')); + } + + $table = $this->getTable(); + + foreach ($pks as $pk) + { + if ($table->load($pk, true)) + { + // Reset the id to create a new record. + $table->id = 0; + + // Alter the title. + $m = null; + if (preg_match('#\((\d+)\)$#', $table->title, $m)) + { + $table->title = preg_replace('#\(\d+\)$#', '(' . ($m[1] + 1) . ')', $table->title); + } + else + { + $table->title .= ' (2)'; + } + // Unpublish duplicate module + $table->published = 0; + + if (!$table->check() || !$table->store()) + { + throw new Exception($table->getError()); + } + + // $query = 'SELECT menuid' + // . ' FROM #__modules_menu' + // . ' WHERE moduleid = ' . (int) $pk + // ; + + $query = $db->getQuery(true) + ->select('menuid') + ->from('#__modules_menu') + ->where('moduleid=' . (int) $pk); + + $this->_db->setQuery($query); + $rows = $this->_db->loadColumn(); + + foreach ($rows as $menuid) + { + $tuples[] = '(' . (int) $table->id . ',' . (int) $menuid . ')'; + } + } + else + { + throw new Exception($table->getError()); + } + } + + if (!empty($tuples)) + { + // Module-Menu Mapping: Do it in one query + $query = 'INSERT INTO #__modules_menu (moduleid,menuid) VALUES ' . implode(',', $tuples); + $this->_db->setQuery($query); + + try + { + $this->_db->execute(); + } + catch (RuntimeException $e) + { + return JError::raiseWarning(500, $e->getMessage()); + } + } + + // Clear modules cache + $this->cleanCache(); + + return true; + } + + /** + * Method to change the title. + * + * @param integer $category_id The id of the category. Not used here. + * @param string $title The title. + * @param string $position The position. + * + * @return array Contains the modified title. + * + * @since 2.5 + */ + protected function generateNewTitle($category_id, $title, $position) + { + // Alter the title & alias + $table = $this->getTable(); + while ($table->load(array('position' => $position, 'title' => $title))) + { + $title = JString::increment($title); + } + + return array($title); + } + + /** + * Method to get the client object + * + * @return void + * + * @since 1.6 + */ + public function &getClient() + { + return $this->_client; + } + + /** + * Method to get the record form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * + * @return JForm A JForm object on success, false on failure + * + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + // The folder and element vars are passed when saving the form. + if (empty($data)) + { + $item = $this->getItem(); + $clientId = $item->client_id; + $module = $item->module; + } + else + { + $clientId = JArrayHelper::getValue($data, 'client_id'); + $module = JArrayHelper::getValue($data, 'module'); + } + + // These variables are used to add data from the plugin XML files. + $this->setState('item.client_id', $clientId); + $this->setState('item.module', $module); + + // Get the form. + $form = $this->loadForm('com_modules.module', 'module', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + $form->setFieldAttribute('position', 'client', $this->getState('item.client_id') == 0 ? 'site' : 'administrator'); + + // Modify the form based on access controls. + if (!$this->canEditState((object) $data)) + { + // Disable fields for display. + $form->setFieldAttribute('ordering', 'disabled', 'true'); + $form->setFieldAttribute('published', 'disabled', 'true'); + $form->setFieldAttribute('publish_up', 'disabled', 'true'); + $form->setFieldAttribute('publish_down', 'disabled', 'true'); + + // Disable fields while saving. + // The controller has already verified this is a record you can edit. + $form->setFieldAttribute('ordering', 'filter', 'unset'); + $form->setFieldAttribute('published', 'filter', 'unset'); + $form->setFieldAttribute('publish_up', 'filter', 'unset'); + $form->setFieldAttribute('publish_down', 'filter', 'unset'); + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * + * @since 1.6 + */ + protected function loadFormData() + { + $app = JFactory::getApplication(); + + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_modules.edit.module.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + + // This allows us to inject parameter settings into a new module. + $params = $app->getUserState('com_modules.add.module.params'); + if (is_array($params)) + { + $data->set('params', $params); + } + } + + $this->preprocessData('com_modules.module', $data); + + return $data; + } + + /** + * Method to get a single record. + * + * @param integer $pk The id of the primary key. + * + * @return mixed Object on success, false on failure. + * + * @since 1.6 + */ + public function getItem($pk = null) + { + $pk = (!empty($pk)) ? (int) $pk : (int) $this->getState('module.id'); + $db = $this->getDbo(); + + if (!isset($this->_cache[$pk])) + { + $false = false; + + // Get a row instance. + $table = $this->getTable(); + + // Attempt to load the row. + $return = $table->load($pk); + + // Check for a table object error. + if ($return === false && $error = $table->getError()) + { + $this->setError($error); + return $false; + } + + // Check if we are creating a new extension. + if (empty($pk)) + { + if ($extensionId = (int) $this->getState('extension.id')) + { + $query = $db->getQuery(true) + ->select('element, client_id') + ->from('#__extensions') + ->where('extension_id = ' . $extensionId) + ->where('type = ' . $db->quote('module')); + $db->setQuery($query); + + try + { + $extension = $db->loadObject(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage); + return false; + } + + if (empty($extension)) + { + $this->setError('COM_MODULES_ERROR_CANNOT_FIND_MODULE'); + return false; + } + + // Extension found, prime some module values. + $table->module = $extension->element; + $table->client_id = $extension->client_id; + } + else + { + $app = JFactory::getApplication(); + $app->redirect(JRoute::_('index.php?option=com_modules&view=modules', false)); + return false; + } + } + + // Convert to the JObject before adding other data. + $properties = $table->getProperties(1); + $this->_cache[$pk] = JArrayHelper::toObject($properties, 'JObject'); + + // Convert the params field to an array. + $registry = new JRegistry; + $registry->loadString($table->params); + $this->_cache[$pk]->params = $registry->toArray(); + + // Determine the page assignment mode. + $db->setQuery( + 'SELECT menuid' . + ' FROM #__modules_menu' . + ' WHERE moduleid = ' . $pk + ); + $assigned = $db->loadColumn(); + + if (empty($pk)) + { + // If this is a new module, assign to all pages. + $assignment = 0; + } + elseif (empty($assigned)) + { + // For an existing module it is assigned to none. + $assignment = '-'; + } + else + { + if ($assigned[0] > 0) + { + $assignment = +1; + } + elseif ($assigned[0] < 0) + { + $assignment = -1; + } + else + { + $assignment = 0; + } + } + + $this->_cache[$pk]->assigned = $assigned; + $this->_cache[$pk]->assignment = $assignment; + + // Get the module XML. + $client = JApplicationHelper::getClientInfo($table->client_id); + $path = JPath::clean($client->path . '/modules/' . $table->module . '/' . $table->module . '.xml'); + + if (file_exists($path)) + { + $this->_cache[$pk]->xml = simplexml_load_file($path); + } + else + { + $this->_cache[$pk]->xml = null; + } + } + + return $this->_cache[$pk]; + } + + /** + * Get the necessary data to load an item help screen. + * + * @return object An object with key, url, and local properties for loading the item help screen. + * + * @since 1.6 + */ + public function getHelp() + { + return (object) array('key' => $this->helpKey, 'url' => $this->helpURL); + } + + /** + * Returns a reference to the a Table object, always creating it. + * + * @param string $type The table type to instantiate + * @param string $prefix A prefix for the table class name. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return JTable A database object + * + * @since 1.6 + */ + public function getTable($type = 'Module', $prefix = 'JTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Prepare and sanitise the table prior to saving. + * + * @param JTable $table The database object + * + * @return void + * + * @since 1.6 + */ + protected function prepareTable($table) + { + $table->title = htmlspecialchars_decode($table->title, ENT_QUOTES); + } + + /** + * Method to preprocess the form + * + * @param JForm $form A form object. + * @param mixed $data The data expected for the form. + * @param string $group The name of the plugin group to import (defaults to "content"). + * + * @return void + * + * @since 1.6 + * @throws Exception if there is an error loading the form. + */ + protected function preprocessForm(JForm $form, $data, $group = 'content') + { + jimport('joomla.filesystem.path'); + + $lang = JFactory::getLanguage(); + $clientId = $this->getState('item.client_id'); + $module = $this->getState('item.module'); + + $client = JApplicationHelper::getClientInfo($clientId); + $formFile = JPath::clean($client->path . '/modules/' . $module . '/' . $module . '.xml'); + + // Load the core and/or local language file(s). + $lang->load($module, $client->path, null, false, false) + || $lang->load($module, $client->path . '/modules/' . $module, null, false, false) + || $lang->load($module, $client->path, $lang->getDefault(), false, false) + || $lang->load($module, $client->path . '/modules/' . $module, $lang->getDefault(), false, false); + + if (file_exists($formFile)) + { + // Get the module form. + if (!$form->loadFile($formFile, false, '//config')) + { + throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); + } + + // Attempt to load the xml file. + if (!$xml = simplexml_load_file($formFile)) + { + throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); + } + + // Get the help data from the XML file if present. + $help = $xml->xpath('/extension/help'); + if (!empty($help)) + { + $helpKey = trim((string) $help[0]['key']); + $helpURL = trim((string) $help[0]['url']); + + $this->helpKey = $helpKey ? $helpKey : $this->helpKey; + $this->helpURL = $helpURL ? $helpURL : $this->helpURL; + } + + } + + // Load the default advanced params + JForm::addFormPath(JPATH_ADMINISTRATOR . '/components/com_modules/models/forms'); + $form->loadFile('advanced', false); + + // Trigger the default form events. + parent::preprocessForm($form, $data, $group); + } + + /** + * Loads ContentHelper for filters before validating data. + * + * @param object $form The form to validate against. + * @param array $data The data to validate. + * @param string $group The name of the group(defaults to null). + * + * @return mixed Array of filtered data if valid, false otherwise. + * + * @since 1.1 + */ + public function validate($form, $data, $group = null) + { + require_once JPATH_ADMINISTRATOR . '/components/com_content/helpers/content.php'; + + return parent::validate($form, $data, $group); + } + + /** + * Method to save the form data. + * + * @param array $data The form data. + * + * @return boolean True on success. + * + * @since 1.6 + */ + public function save($data) + { + $dispatcher = JEventDispatcher::getInstance(); + $input = JFactory::getApplication()->input; + $table = $this->getTable(); + $pk = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('module.id'); + $isNew = true; + + // Include the content modules for the onSave events. + JPluginHelper::importPlugin('extension'); + + // Load the row if saving an existing record. + if ($pk > 0) + { + $table->load($pk); + $isNew = false; + } + + // Alter the title and published state for Save as Copy + if ($input->get('task') == 'save2copy') + { + $orig_data = $input->post->get('jform', array(), 'array'); + $orig_table = clone($this->getTable()); + $orig_table->load((int) $orig_data['id']); + + if ($data['title'] == $orig_table->title) + { + $data['title'] .= ' ' . JText::_('JGLOBAL_COPY'); + $data['published'] = 0; + } + } + + // Bind the data. + if (!$table->bind($data)) + { + $this->setError($table->getError()); + return false; + } + + // Prepare the row for saving + $this->prepareTable($table); + + // Check the data. + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // Trigger the onExtensionBeforeSave event. + $result = $dispatcher->trigger('onExtensionBeforeSave', array('com_modules.module', &$table, $isNew)); + if (in_array(false, $result, true)) + { + $this->setError($table->getError()); + return false; + } + + // Store the data. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Process the menu link mappings. + $assignment = isset($data['assignment']) ? $data['assignment'] : 0; + + // Delete old module to menu item associations + // $db->setQuery( + // 'DELETE FROM #__modules_menu'. + // ' WHERE moduleid = '.(int) $table->id + // ); + + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->delete('#__modules_menu') + ->where('moduleid = ' . (int) $table->id); + $db->setQuery($query); + + try + { + $db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + // If the assignment is numeric, then something is selected (otherwise it's none). + if (is_numeric($assignment)) + { + // Variable is numeric, but could be a string. + $assignment = (int) $assignment; + + // Logic check: if no module excluded then convert to display on all. + if ($assignment == -1 && empty($data['assigned'])) + { + $assignment = 0; + } + + // Check needed to stop a module being assigned to `All` + // and other menu items resulting in a module being displayed twice. + if ($assignment === 0) + { + // Assign new module to `all` menu item associations. + // $this->_db->setQuery( + // 'INSERT INTO #__modules_menu'. + // ' SET moduleid = ' . (int) $table->id . ', menuid = 0' + // ) + + $query->clear() + ->insert('#__modules_menu') + ->columns(array($db->quoteName('moduleid'), $db->quoteName('menuid'))) + ->values((int) $table->id . ', 0'); + $db->setQuery($query); + + try + { + $db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + } + elseif (!empty($data['assigned'])) + { + // Get the sign of the number. + $sign = $assignment < 0 ? -1 : +1; + + // Preprocess the assigned array. + $tuples = array(); + foreach ($data['assigned'] as &$pk) + { + $tuples[] = '(' . (int) $table->id . ',' . (int) $pk * $sign . ')'; + } + + $this->_db->setQuery( + 'INSERT INTO #__modules_menu (moduleid, menuid) VALUES ' . + implode(',', $tuples) + ); + + try + { + $db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + } + } + + // Trigger the onExtensionAfterSave event. + $dispatcher->trigger('onExtensionAfterSave', array('com_modules.module', &$table, $isNew)); + + // Compute the extension id of this module in case the controller wants it. + $query = $db->getQuery(true) + ->select('extension_id') + ->from('#__extensions AS e') + ->join('LEFT', '#__modules AS m ON e.element = m.module') + ->where('m.id = ' . (int) $table->id); + $db->setQuery($query); + + try + { + $extensionId = $db->loadResult(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + return false; + } + + $this->setState('module.extension_id', $extensionId); + $this->setState('module.id', $table->id); + + // Clear modules cache + $this->cleanCache(); + + // Clean module cache + parent::cleanCache($table->module, $table->client_id); + + return true; + } + + /** + * A protected method to get a set of ordering conditions. + * + * @param object $table A record object. + * + * @return array An array of conditions to add to add to ordering queries. + * + * @since 1.6 + */ + protected function getReorderConditions($table) + { + $condition = array(); + $condition[] = 'client_id = ' . (int) $table->client_id; + $condition[] = 'position = ' . $this->_db->quote($table->position); + + return $condition; + } + + /** + * Custom clean cache method for different clients + * + * @param string $group The name of the plugin group to import (defaults to null). + * @param integer $client_id The client ID. [optional] + * + * @return void + * + * @since 1.6 + */ + protected function cleanCache($group = null, $client_id = 0) + { + parent::cleanCache('com_modules', $this->getClient()); + } +} diff --git a/administrator/components/com_modules/models/modules.php b/administrator/components/com_modules/models/modules.php new file mode 100644 index 0000000..992ecb2 --- /dev/null +++ b/administrator/components/com_modules/models/modules.php @@ -0,0 +1,326 @@ +getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $accessId = $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access', null, 'int'); + $this->setState('filter.access', $accessId); + + $state = $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string'); + $this->setState('filter.state', $state); + + $position = $this->getUserStateFromRequest($this->context . '.filter.position', 'filter_position', '', 'string'); + $this->setState('filter.position', $position); + + $module = $this->getUserStateFromRequest($this->context . '.filter.module', 'filter_module', '', 'string'); + $this->setState('filter.module', $module); + + $clientId = $this->getUserStateFromRequest($this->context . '.filter.client_id', 'filter_client_id', 0, 'int', false); + $previousId = $app->getUserState($this->context . '.filter.client_id_previous', null); + if ($previousId != $clientId || $previousId === null) + { + $this->getUserStateFromRequest($this->context . '.filter.client_id_previous', 'filter_client_id_previous', 0, 'int', true); + $app->setUserState($this->context . '.filter.client_id_previous', $clientId); + } + $this->setState('filter.client_id', $clientId); + + $language = $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', ''); + $this->setState('filter.language', $language); + + // Load the parameters. + $params = JComponentHelper::getParams('com_modules'); + $this->setState('params', $params); + + // List state information. + parent::populateState('position', 'asc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string A prefix for the store id. + * + * @return string A store id. + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.access'); + $id .= ':' . $this->getState('filter.state'); + $id .= ':' . $this->getState('filter.position'); + $id .= ':' . $this->getState('filter.module'); + $id .= ':' . $this->getState('filter.client_id'); + $id .= ':' . $this->getState('filter.language'); + + return parent::getStoreId($id); + } + + /** + * Returns an object list + * + * @param string The query + * @param int Offset + * @param int The number of records + * @return array + */ + protected function _getList($query, $limitstart = 0, $limit = 0) + { + $ordering = $this->getState('list.ordering', 'ordering'); + if (in_array($ordering, array('pages', 'name'))) + { + $this->_db->setQuery($query); + $result = $this->_db->loadObjectList(); + $this->translate($result); + JArrayHelper::sortObjects($result, $ordering, $this->getState('list.direction') == 'desc' ? -1 : 1, true, true); + $total = count($result); + $this->cache[$this->getStoreId('getTotal')] = $total; + if ($total < $limitstart) + { + $limitstart = 0; + $this->setState('list.start', 0); + } + return array_slice($result, $limitstart, $limit ? $limit : null); + } + else + { + if ($ordering == 'ordering') + { + $query->order('a.position ASC'); + $ordering = 'a.ordering'; + } + if ($ordering == 'language_title') + { + $ordering = 'l.title'; + } + $query->order($this->_db->quoteName($ordering) . ' ' . $this->getState('list.direction')); + if ($ordering == 'position') + { + $query->order('a.ordering ASC'); + } + $result = parent::_getList($query, $limitstart, $limit); + $this->translate($result); + return $result; + } + } + + /** + * Translate a list of objects + * + * @param array The array of objects + * @return array The array of translated objects + */ + protected function translate(&$items) + { + $lang = JFactory::getLanguage(); + $client = $this->getState('filter.client_id') ? 'administrator' : 'site'; + + foreach ($items as $item) + { + $extension = $item->module; + $source = constant('JPATH_' . strtoupper($client)) . "/modules/$extension"; + $lang->load("$extension.sys", constant('JPATH_' . strtoupper($client)), null, false, false) + || $lang->load("$extension.sys", $source, null, false, false) + || $lang->load("$extension.sys", constant('JPATH_' . strtoupper($client)), $lang->getDefault(), false, false) + || $lang->load("$extension.sys", $source, $lang->getDefault(), false, false); + $item->name = JText::_($item->name); + if (is_null($item->pages)) + { + $item->pages = JText::_('JNONE'); + } + elseif ($item->pages < 0) + { + $item->pages = JText::_('COM_MODULES_ASSIGNED_VARIES_EXCEPT'); + } + elseif ($item->pages > 0) + { + $item->pages = JText::_('COM_MODULES_ASSIGNED_VARIES_ONLY'); + } + else + { + $item->pages = JText::_('JALL'); + } + } + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.id, a.title, a.note, a.position, a.module, a.language,' . + 'a.checked_out, a.checked_out_time, a.published+2*(e.enabled-1) as published, a.access, a.ordering, a.publish_up, a.publish_down' + ) + ); + $query->from($db->quoteName('#__modules') . ' AS a'); + + // Join over the language + $query->select('l.title AS language_title') + ->join('LEFT', $db->quoteName('#__languages') . ' AS l ON l.lang_code = a.language'); + + // Join over the users for the checked out user. + $query->select('uc.name AS editor') + ->join('LEFT', '#__users AS uc ON uc.id=a.checked_out'); + + // Join over the asset groups. + $query->select('ag.title AS access_level') + ->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access'); + + // Join over the module menus + $query->select('MIN(mm.menuid) AS pages') + ->join('LEFT', '#__modules_menu AS mm ON mm.moduleid = a.id'); + + // Join over the extensions + $query->select('e.name AS name') + ->join('LEFT', '#__extensions AS e ON e.element = a.module') + ->group( + 'a.id, a.title, a.note, a.position, a.module, a.language,a.checked_out,' . + 'a.checked_out_time, a.published, a.access, a.ordering,l.title, uc.name, ag.title, e.name,' . + 'l.lang_code, uc.id, ag.id, mm.moduleid, e.element, a.publish_up, a.publish_down,e.enabled' + ); + + // Filter by access level. + if ($access = $this->getState('filter.access')) + { + $query->where('a.access = ' . (int) $access); + } + + // Filter by published state + $state = $this->getState('filter.state'); + if (is_numeric($state)) + { + $query->where('a.published = ' . (int) $state); + } + elseif ($state === '') + { + $query->where('(a.published IN (0, 1))'); + } + + // Filter by position + $position = $this->getState('filter.position'); + if ($position && $position != 'none') + { + $query->where('a.position = ' . $db->quote($position)); + } + + elseif ($position == 'none') + { + $query->where('a.position = ' . $db->quote('')); + } + + // Filter by module + $module = $this->getState('filter.module'); + if ($module) + { + $query->where('a.module = ' . $db->quote($module)); + } + + // Filter by client. + $clientId = $this->getState('filter.client_id'); + if (is_numeric($clientId)) + { + $query->where('a.client_id = ' . (int) $clientId . ' AND e.client_id =' . (int) $clientId); + } + + // Filter by search in title + $search = $this->getState('filter.search'); + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + else + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('(' . 'a.title LIKE ' . $search . ' OR a.note LIKE ' . $search . ')'); + } + } + + // Filter on the language. + if ($language = $this->getState('filter.language')) + { + $query->where('a.language = ' . $db->quote($language)); + } + + //echo nl2br(str_replace('#__','jos_',$query)); + return $query; + } +} diff --git a/administrator/components/com_modules/models/positions.php b/administrator/components/com_modules/models/positions.php new file mode 100644 index 0000000..1a73ab2 --- /dev/null +++ b/administrator/components/com_modules/models/positions.php @@ -0,0 +1,219 @@ +getUserStateFromRequest($this->context.'.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $state = $this->getUserStateFromRequest($this->context.'.filter.state', 'filter_state', '', 'string'); + $this->setState('filter.state', $state); + + $clientId = $app->input->getInt('client_id', 0); + $this->setState('filter.client_id', $clientId); + + $template = $this->getUserStateFromRequest($this->context.'.filter.template', 'filter_template', '', 'string'); + $this->setState('filter.template', $template); + + $type = $this->getUserStateFromRequest($this->context.'.filter.type', 'filter_type', '', 'string'); + $this->setState('filter.type', $type); + + // Load the parameters. + $params = JComponentHelper::getParams('com_modules'); + $this->setState('params', $params); + + // List state information. + parent::populateState('value', 'asc'); + } + + /** + * Method to get an array of data items. + * + * @return mixed An array of data items on success, false on failure. + * @since 1.6 + */ + public function getItems() + { + if (!isset($this->items)) + { + $lang = JFactory::getLanguage(); + $search = $this->getState('filter.search'); + $state = $this->getState('filter.state'); + $clientId = $this->getState('filter.client_id'); + $filter_template = $this->getState('filter.template'); + $type = $this->getState('filter.type'); + $ordering = $this->getState('list.ordering'); + $direction = $this->getState('list.direction'); + $limitstart = $this->getState('list.start'); + $limit = $this->getState('list.limit'); + $client = JApplicationHelper::getClientInfo($clientId); + + if ($type != 'template') + { + // Get the database object and a new query object. + $query = $this->_db->getQuery(true) + ->select('DISTINCT(position) as value') + ->from('#__modules') + ->where($this->_db->quoteName('client_id').' = '.(int) $clientId); + if ($search) + { + $query->where('position LIKE '.$this->_db->quote('%'.$this->_db->escape($search, true).'%')); + } + + $this->_db->setQuery($query); + + try + { + $positions = $this->_db->loadObjectList('value'); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + foreach ($positions as $value => $position) + { + $positions[$value] = array(); + } + } + else + { + $positions = array(); + } + + // Load the positions from the installed templates. + foreach (ModulesHelper::getTemplates($clientId) as $template) + { + $path = JPath::clean($client->path.'/templates/'.$template->element.'/templateDetails.xml'); + + if (file_exists($path)) + { + $xml = simplexml_load_file($path); + if (isset($xml->positions[0])) + { + $lang->load('tpl_'.$template->element.'.sys', $client->path, null, false, false) + || $lang->load('tpl_'.$template->element.'.sys', $client->path.'/templates/'.$template->element, null, false, false) + || $lang->load('tpl_'.$template->element.'.sys', $client->path, $lang->getDefault(), false, false) + || $lang->load('tpl_'.$template->element.'.sys', $client->path.'/templates/'.$template->element, $lang->getDefault(), false, false); + foreach ($xml->positions[0] as $position) + { + $value = (string) $position['value']; + $label = (string) $position; + if (!$value) + { + $value = $label; + $label = preg_replace('/[^a-zA-Z0-9_\-]/', '_', 'TPL_'.$template->element.'_POSITION_'.$value); + $altlabel = preg_replace('/[^a-zA-Z0-9_\-]/', '_', 'COM_MODULES_POSITION_'.$value); + if (!$lang->hasKey($label) && $lang->hasKey($altlabel)) + { + $label = $altlabel; + } + } + if ($type == 'user' || ($state != '' && $state != $template->enabled)) + { + unset($positions[$value]); + } + elseif (preg_match(chr(1) . $search . chr(1) . 'i', $value) && ($filter_template == '' || $filter_template == $template->element)) + { + if (!isset($positions[$value])) + { + $positions[$value] = array(); + } + $positions[$value][$template->name] = $label; + } + } + } + } + } + $this->total = count($positions); + if ($limitstart >= $this->total) + { + $limitstart = $limitstart < $limit ? 0 : $limitstart - $limit; + $this->setState('list.start', $limitstart); + } + if ($ordering == 'value') + { + if ($direction == 'asc') + { + ksort($positions); + } + else { + krsort($positions); + } + } + else { + if ($direction == 'asc') + { + asort($positions); + } + else { + arsort($positions); + } + } + $this->items = array_slice($positions, $limitstart, $limit ? $limit : null); + } + return $this->items; + } + + /** + * Method to get the total number of items. + * + * @return int The total number of items. + * @since 1.6 + */ + public function getTotal() + { + if (!isset($this->total)) + { + $this->getItems(); + } + return $this->total; + } +} diff --git a/administrator/components/com_modules/models/select.php b/administrator/components/com_modules/models/select.php new file mode 100644 index 0000000..28b0571 --- /dev/null +++ b/administrator/components/com_modules/models/select.php @@ -0,0 +1,153 @@ +getUserState('com_modules.modules.filter.client_id', 0); + $this->setState('filter.client_id', (int) $clientId); + + // Load the parameters. + $params = JComponentHelper::getParams('com_modules'); + $this->setState('params', $params); + + // Manually set limits to get all modules. + $this->setState('list.limit', 0); + $this->setState('list.start', 0); + $this->setState('list.ordering', 'a.name'); + $this->setState('list.direction', 'ASC'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string A prefix for the store id. + * + * @return string A store id. + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.client_id'); + + return parent::getStoreId($id); + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.extension_id, a.name, a.element AS module' + ) + ); + $query->from($db->quoteName('#__extensions') . ' AS a'); + + // Filter by module + $query->where('a.type = ' . $db->quote('module')); + + // Filter by client. + $clientId = $this->getState('filter.client_id'); + $query->where('a.client_id = ' . (int) $clientId); + + // Filter by enabled + $query->where('a.enabled = 1'); + + // Add the list ordering clause. + $query->order($db->escape($this->getState('list.ordering', 'a.ordering')) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))); + + //echo nl2br(str_replace('#__','jos_',$query)); + return $query; + } + + /** + * Method to get a list of items. + * + * @return mixed An array of objects on success, false on failure. + */ + public function &getItems() + { + // Get the list of items from the database. + $items = parent::getItems(); + + $client = JApplicationHelper::getClientInfo($this->getState('filter.client_id', 0)); + $lang = JFactory::getLanguage(); + + // Loop through the results to add the XML metadata, + // and load language support. + foreach ($items as &$item) + { + $path = JPath::clean($client->path . '/modules/' . $item->module . '/' . $item->module . '.xml'); + if (file_exists($path)) + { + $item->xml = simplexml_load_file($path); + } + else + { + $item->xml = null; + } + + // 1.5 Format; Core files or language packs then + // 1.6 3PD Extension Support + $lang->load($item->module . '.sys', $client->path, null, false, false) + || $lang->load($item->module . '.sys', $client->path . '/modules/' . $item->module, null, false, false) + || $lang->load($item->module . '.sys', $client->path, $lang->getDefault(), false, false) + || $lang->load($item->module . '.sys', $client->path . '/modules/' . $item->module, $lang->getDefault(), false, false); + $item->name = JText::_($item->name); + + if (isset($item->xml) && $text = trim($item->xml->description)) + { + $item->desc = JText::_($text); + } + else + { + $item->desc = JText::_('COM_MODULES_NODESCRIPTION'); + } + } + $items = JArrayHelper::sortObjects($items, 'name', 1, true, true); + + // TODO: Use the cached XML from the extensions table? + + return $items; + } +} diff --git a/administrator/components/com_modules/modules.php b/administrator/components/com_modules/modules.php new file mode 100644 index 0000000..d3f5845 --- /dev/null +++ b/administrator/components/com_modules/modules.php @@ -0,0 +1,19 @@ +authorise('core.manage', 'com_modules')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$controller = JControllerLegacy::getInstance('Modules'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_modules/modules.xml b/administrator/components/com_modules/modules.xml new file mode 100644 index 0000000..748d79b --- /dev/null +++ b/administrator/components/com_modules/modules.xml @@ -0,0 +1,28 @@ + + + com_modules + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_MODULES_XML_DESCRIPTION + + + config.xml + controller.php + index.html + modules.php + controllers + helpers + models + views + + + language/en-GB.com_modules.ini + language/en-GB.com_modules.sys.ini + + + diff --git a/administrator/components/com_modules/views/index.html b/administrator/components/com_modules/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/views/module/index.html b/administrator/components/com_modules/views/module/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/views/module/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/views/module/tmpl/edit.php b/administrator/components/com_modules/views/module/tmpl/edit.php new file mode 100644 index 0000000..83d4abe --- /dev/null +++ b/administrator/components/com_modules/views/module/tmpl/edit.php @@ -0,0 +1,193 @@ +item->module) || $this->item->module == 'custom' || $this->item->module == 'mod_custom'; + +// Get Params Fieldsets +$this->fieldsets = $this->form->getFieldsets('params'); + + +$script = "Joomla.submitbutton = function(task) + { + if (task == 'module.cancel' || document.formvalidator.isValid(document.id('module-form'))) {"; +if ($hasContent) +{ + $script .= $this->form->getField('content')->save(); +} +$script .= " Joomla.submitform(task, document.getElementById('module-form')); + if (self != top) + { + window.top.setTimeout('window.parent.SqueezeBox.close()', 1000); + } + } + }"; + +JFactory::getDocument()->addScriptDeclaration($script); +?> +
    +
    + + +
    +
    +
    +
    +
    +
    + form->getLabel('title'); ?> +
    +
    + form->getInput('title'); ?> +
    +
    +
    +
    + form->getLabel('showtitle'); ?> +
    +
    + form->getInput('showtitle'); ?> +
    +
    +
    +
    + form->getLabel('position'); ?> +
    +
    + loadTemplate('positions'); ?> +
    +
    +
    + item->xml->name != 'Login Form') : ?> +
    +
    + form->getLabel('published'); ?> +
    +
    + form->getInput('published'); ?> +
    +
    + +
    +
    + form->getLabel('access'); ?> +
    +
    + form->getInput('access'); ?> +
    +
    +
    +
    + form->getLabel('ordering'); ?> +
    +
    + form->getInput('ordering'); ?> +
    +
    + item->xml->name != 'Login Form') : ?> +
    +
    + form->getLabel('publish_up'); ?> +
    +
    + form->getInput('publish_up'); ?> +
    +
    +
    +
    + form->getLabel('publish_down'); ?> +
    +
    + form->getInput('publish_down'); ?> +
    +
    + + +
    +
    + form->getLabel('language'); ?> +
    +
    + form->getInput('language'); ?> +
    +
    +
    +
    + form->getLabel('note'); ?> +
    +
    + form->getInput('note'); ?> +
    +
    +
    +
    + item->xml) : ?> + item->xml->description)) : ?> +
    +

    + + item->id) : ?> + : item->id; ?> + +

    +
    +
    + +
    +
    +
    + item->client_id == 0 ? JText::_('JSITE') : JText::_('JADMINISTRATOR'); ?> / item->xml) echo ($text = (string) $this->item->xml->name) ? JText::_($text) : $this->item->module;else echo JText::_('COM_MODULES_ERR_XML');?> +
    +
    + + +
    + +
    +
    +
    +
    + loadTemplate('options'); ?> +
    + + +
    + form->getInput('content'); ?> +
    + + item->client_id == 0) : ?> +
    + loadTemplate('assignment'); ?> +
    + +
    + + + + form->getInput('module'); ?> + form->getInput('client_id'); ?> +
    +
    diff --git a/administrator/components/com_modules/views/module/tmpl/edit_assignment.php b/administrator/components/com_modules/views/module/tmpl/edit_assignment.php new file mode 100644 index 0000000..4ba4ef5 --- /dev/null +++ b/administrator/components/com_modules/views/module/tmpl/edit_assignment.php @@ -0,0 +1,150 @@ +addScriptDeclaration($script); +?> +
    + + +
    + +
    +
    + diff --git a/administrator/components/com_modules/views/module/tmpl/edit_options.php b/administrator/components/com_modules/views/module/tmpl/edit_options.php new file mode 100644 index 0000000..4990670 --- /dev/null +++ b/administrator/components/com_modules/views/module/tmpl/edit_options.php @@ -0,0 +1,38 @@ + + 'collapse0')); + $fieldSets = $this->form->getFieldsets('params'); + $i = 0; + + foreach ($fieldSets as $name => $fieldSet) : + $label = !empty($fieldSet->label) ? $fieldSet->label : 'COM_MODULES_'.$name.'_FIELDSET_LABEL'; + $class = isset($fieldSet->class) && !empty($fieldSet->class) ? $fieldSet->class : ''; + + echo JHtml::_('bootstrap.addSlide', 'moduleOptions', JText::_($label), 'collapse' . $i++, $class); + if (isset($fieldSet->description) && trim($fieldSet->description)) : + echo '

    '.$this->escape(JText::_($fieldSet->description)).'

    '; + endif; + ?> + form->getFieldset($name) as $field) : ?> +
    +
    + label; ?> +
    +
    + input; ?> +
    +
    + item->client_id; +$state = 1; +$selectedPosition = $this->item->position; +$positions = JHtml::_('modules.positions', $clientId, $state, $selectedPosition); + + +// Add custom position to options +$customGroupText = JText::_('COM_MODULES_CUSTOM_POSITION'); + +// Build field +$attr = array( + 'id' => 'jform_position', + 'list.select' => $this->item->position, + 'list.attr' => 'class="chzn-custom-value input-xlarge" ' + . 'data-custom_group_text="' . $customGroupText . '" ' + . 'data-no_results_text="' . JText::_('COM_MODULES_ADD_CUSTOM_POSITION') . '" ' + . 'data-placeholder="' . JText::_('COM_MODULES_TYPE_OR_SELECT_POSITION') . '" ' +); + +echo JHtml::_('select.groupedlist', $positions, 'jform[position]', $attr); diff --git a/administrator/components/com_modules/views/module/tmpl/index.html b/administrator/components/com_modules/views/module/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/views/module/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/views/module/tmpl/modal.php b/administrator/components/com_modules/views/module/tmpl/modal.php new file mode 100644 index 0000000..499edd0 --- /dev/null +++ b/administrator/components/com_modules/views/module/tmpl/modal.php @@ -0,0 +1,26 @@ + +
    +
    + +
    +
    + +
    +
    +
    + +setLayout('edit'); +echo $this->loadTemplate(); diff --git a/administrator/components/com_modules/views/module/view.html.php b/administrator/components/com_modules/views/module/view.html.php new file mode 100644 index 0000000..d73726a --- /dev/null +++ b/administrator/components/com_modules/views/module/view.html.php @@ -0,0 +1,103 @@ +form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + JFactory::getApplication()->input->set('hidemainmenu', true); + + $user = JFactory::getUser(); + $isNew = ($this->item->id == 0); + $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $user->get('id')); + $canDo = ModulesHelper::getActions($this->state->get('filter.category_id'), $this->item->id); + + JToolbarHelper::title(JText::sprintf('COM_MODULES_MANAGER_MODULE', JText::_($this->item->module)), 'module.png'); + + // If not checked out, can save the item. + if (!$checkedOut && ($canDo->get('core.edit') || $canDo->get('core.create') )) + { + JToolbarHelper::apply('module.apply'); + JToolbarHelper::save('module.save'); + } + if (!$checkedOut && $canDo->get('core.create')) + { + JToolbarHelper::save2new('module.save2new'); + } + // If an existing item, can save to a copy. + if (!$isNew && $canDo->get('core.create')) + { + JToolbarHelper::save2copy('module.save2copy'); + } + if (empty($this->item->id)) + { + JToolbarHelper::cancel('module.cancel'); + } + else + { + JToolbarHelper::cancel('module.cancel', 'JTOOLBAR_CLOSE'); + } + + // Get the help information for the menu item. + $lang = JFactory::getLanguage(); + + $help = $this->get('Help'); + if ($lang->hasKey($help->url)) + { + $debug = $lang->setDebug(false); + $url = JText::_($help->url); + $lang->setDebug($debug); + } + else + { + $url = null; + } + JToolbarHelper::help($help->key, false, $url); + } +} diff --git a/administrator/components/com_modules/views/modules/index.html b/administrator/components/com_modules/views/modules/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/views/modules/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/views/modules/tmpl/default.php b/administrator/components/com_modules/views/modules/tmpl/default.php new file mode 100644 index 0000000..73d681b --- /dev/null +++ b/administrator/components/com_modules/views/modules/tmpl/default.php @@ -0,0 +1,257 @@ +state->get('filter.client_id') ? 'administrator' : 'site'; +$user = JFactory::getUser(); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$trashed = $this->state->get('filter.published') == -2 ? true : false; +$canOrder = $user->authorise('core.edit.state', 'com_modules'); +$saveOrder = $listOrder == 'ordering'; +if ($saveOrder) +{ + $saveOrderingUrl = 'index.php?option=com_modules&task=modules.saveOrderAjax&tmpl=component'; + JHtml::_('sortablelist.sortable', 'articleList', 'adminForm', strtolower($listDirn), $saveOrderingUrl); +} +$sortFields = $this->getSortFields(); +?> + +
    +sidebar)) : ?> +
    + sidebar; ?> +
    +
    + +
    + + +
    + +
    + + +
    +
    + + pagination->getLimitBox(); ?> +
    +
    + + +
    +
    + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + items as $i => $item) : + $ordering = ($listOrder == 'ordering'); + $canCreate = $user->authorise('core.create', 'com_modules'); + $canEdit = $user->authorise('core.edit', 'com_modules'); + $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id')|| $item->checked_out == 0; + $canChange = $user->authorise('core.edit.state', 'com_modules') && $canCheckin; + ?> + + + + + + + + + + + + + + + +
    + ', 'ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING'); ?> + + + + + + + + + + + + + + + + + + +
    + pagination->getListFooter(); ?> +
    + + + + + + + + + id); ?> + + published, $i, $canChange, 'cb'); ?> + +
    + checked_out) : ?> + editor, $item->checked_out_time, 'modules.', $canCheckin); ?> + + + + escape($item->title); ?> + + escape($item->title); ?> + + + note)) : ?> +
    + escape($item->note));?> +
    + +
    +
    + id, 'module.'); + JHtml::_('dropdown.divider'); + if ($item->published) : + JHtml::_('dropdown.unpublish', 'cb' . $i, 'modules.'); + else : + JHtml::_('dropdown.publish', 'cb' . $i, 'modules.'); + endif; + + JHtml::_('dropdown.divider'); + + if ($item->checked_out) : + JHtml::_('dropdown.checkin', 'cb' . $i, 'modules.'); + endif; + + if ($trashed) : + JHtml::_('dropdown.untrash', 'cb' . $i, 'modules.'); + else : + JHtml::_('dropdown.trash', 'cb' . $i, 'modules.'); + endif; + + // Render dropdown list + echo JHtml::_('dropdown.render'); + ?> +
    +
    + position) : ?> + + position; ?> + + + + + + + + name;?> + + pages; ?> + + escape($item->access_level); ?> + + language == ''):?> + + language == '*'):?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + id; ?> +
    + + + loadTemplate('batch'); ?> + + + + + + +
    + diff --git a/administrator/components/com_modules/views/modules/tmpl/default_batch.php b/administrator/components/com_modules/views/modules/tmpl/default_batch.php new file mode 100644 index 0000000..299e00d --- /dev/null +++ b/administrator/components/com_modules/views/modules/tmpl/default_batch.php @@ -0,0 +1,70 @@ +state->get('filter.client_id'); +$published = $this->state->get('filter.published'); +$positions = JHtml::_('modules.positions', $clientId, $published); + +// Add custom position to options +$customGroupText = JText::_('COM_MODULES_CUSTOM_POSITION'); + +// Build field +$attr = array( + 'id' => 'batch-position-id', + 'list.attr' => 'class="chzn-custom-value input-xlarge" ' + . 'data-custom_group_text="' . $customGroupText . '" ' + . 'data-no_results_text="' . JText::_('COM_MODULES_ADD_CUSTOM_POSITION') . '" ' + . 'data-placeholder="' . JText::_('COM_MODULES_TYPE_OR_SELECT_POSITION') . '" ' +); + +?> + diff --git a/administrator/components/com_modules/views/modules/tmpl/index.html b/administrator/components/com_modules/views/modules/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/views/modules/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/views/modules/view.html.php b/administrator/components/com_modules/views/modules/view.html.php new file mode 100644 index 0000000..e50bf41 --- /dev/null +++ b/administrator/components/com_modules/views/modules/view.html.php @@ -0,0 +1,202 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + // Check if there are no matching items + if (!count($this->items)){ + JFactory::getApplication()->enqueueMessage( + JText::_('COM_MODULES_MSG_MANAGE_NO_MODULES'), + 'warning' + ); + } + + $this->addToolbar(); + // Include the component HTML helpers. + JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html'); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + $state = $this->get('State'); + $canDo = ModulesHelper::getActions(); + $user = JFactory::getUser(); + + // Get the toolbar object instance + $bar = JToolBar::getInstance('toolbar'); + + JToolbarHelper::title(JText::_('COM_MODULES_MANAGER_MODULES'), 'module.png'); + + if ($canDo->get('core.create')) + { + $title = JText::_('JTOOLBAR_NEW'); + $dhtml = ""; + $bar->appendButton('Custom', $dhtml, 'new'); + } + + if ($canDo->get('core.edit')) + { + JToolbarHelper::editList('module.edit'); + } + + if ($canDo->get('core.create')) + { + JToolbarHelper::custom('modules.duplicate', 'copy.png', 'copy_f2.png', 'JTOOLBAR_DUPLICATE', true); + } + + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::publish('modules.publish', 'JTOOLBAR_PUBLISH', true); + JToolbarHelper::unpublish('modules.unpublish', 'JTOOLBAR_UNPUBLISH', true); + JToolbarHelper::checkin('modules.checkin'); + } + + if ($state->get('filter.state') == -2 && $canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'modules.delete', 'JTOOLBAR_EMPTY_TRASH'); + } elseif ($canDo->get('core.edit.state')) + { + JToolbarHelper::trash('modules.trash'); + } + + // Add a batch button + if ($user->authorise('core.create', 'com_modules') && $user->authorise('core.edit', 'com_modules') && $user->authorise('core.edit.state', 'com_modules')) + { + JHtml::_('bootstrap.modal', 'collapseModal'); + $title = JText::_('JTOOLBAR_BATCH'); + + // Instantiate a new JLayoutFile instance and render the batch button + $layout = new JLayoutFile('joomla.toolbar.batch'); + + $dhtml = $layout->render(array('title' => $title)); + $bar->appendButton('Custom', $dhtml, 'batch'); + } + + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_modules'); + } + JToolbarHelper::help('JHELP_EXTENSIONS_MODULE_MANAGER'); + + JHtmlSidebar::addEntry( + JText::_('JSITE'), + 'index.php?option=com_modules&filter_client_id=0', + $this->state->get('filter.client_id') == 0 + ); + + JHtmlSidebar::addEntry( + JText::_('JADMINISTRATOR'), + 'index.php?option=com_modules&filter_client_id=1', + $this->state->get('filter.client_id') == 1 + ); + + JHtmlSidebar::setAction('index.php?option=com_modules'); + + JHtmlSidebar::addFilter( + // @todo we need a label for this + '', + 'filter_client_id', + JHtml::_('select.options', ModulesHelper::getClientOptions(), 'value', 'text', $this->state->get('filter.client_id')), + false + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_state', + JHtml::_('select.options', ModulesHelper::getStateOptions(), 'value', 'text', $this->state->get('filter.state')) + ); + + JHtmlSidebar::addFilter( + JText::_('COM_MODULES_OPTION_SELECT_POSITION'), + 'filter_position', + JHtml::_('select.options', ModulesHelper::getPositions($this->state->get('filter.client_id')), 'value', 'text', $this->state->get('filter.position')) + ); + + JHtmlSidebar::addFilter( + JText::_('COM_MODULES_OPTION_SELECT_MODULE'), + 'filter_module', + JHtml::_('select.options', ModulesHelper::getModules($this->state->get('filter.client_id')), 'value', 'text', $this->state->get('filter.module')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_ACCESS'), + 'filter_access', + JHtml::_('select.options', JHtml::_('access.assetgroups'), 'value', 'text', $this->state->get('filter.access')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_LANGUAGE'), + 'filter_language', + JHtml::_('select.options', JHtml::_('contentlanguage.existing', true, true), 'value', 'text', $this->state->get('filter.language')) + ); + + $this->sidebar = JHtmlSidebar::render(); + } + + /** + * Returns an array of fields the table can be sorted by + * + * @return array Array containing the field name to sort by as the key and display text as value + * + * @since 3.0 + */ + protected function getSortFields() + { + return array( + 'ordering' => JText::_('JGRID_HEADING_ORDERING'), + 'a.published' => JText::_('JSTATUS'), + 'a.title' => JText::_('JGLOBAL_TITLE'), + 'position' => JText::_('COM_MODULES_HEADING_POSITION'), + 'name' => JText::_('COM_MODULES_HEADING_MODULE'), + 'pages' => JText::_('COM_MODULES_HEADING_PAGES'), + 'a.access' => JText::_('JGRID_HEADING_ACCESS'), + 'language_title' => JText::_('JGRID_HEADING_LANGUAGE'), + 'a.id' => JText::_('JGRID_HEADING_ID') + ); + } +} diff --git a/administrator/components/com_modules/views/positions/index.html b/administrator/components/com_modules/views/positions/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/views/positions/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/views/positions/tmpl/index.html b/administrator/components/com_modules/views/positions/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/views/positions/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/views/positions/tmpl/modal.php b/administrator/components/com_modules/views/positions/tmpl/modal.php new file mode 100644 index 0000000..7dfb0e6 --- /dev/null +++ b/administrator/components/com_modules/views/positions/tmpl/modal.php @@ -0,0 +1,104 @@ +input->getCmd('function', 'jSelectPosition'); +$lang = JFactory::getLanguage(); +$ordering = $this->escape($this->state->get('list.ordering')); +$direction = $this->escape($this->state->get('list.direction')); +$clientId = $this->state->get('filter.client_id'); +$state = $this->state->get('filter.state'); +$template = $this->state->get('filter.template'); +$type = $this->state->get('filter.type'); +?> +
    +
    +
    + + + + + +
    + +
    + + + + + +
    +
    + + + + + + + + + + + + + + + items as $value => $templates) : ?> + + + + + + +
    + + + +
    + pagination->getListFooter(); ?> +
    + escape($value); ?> + + + +
      + $label):?> +
    • hasKey($label) ? JText::sprintf('COM_MODULES_MODULE_TEMPLATE_POSITION', JText::_($template), JText::_($label)) : JText::_($template);?>
    • + +
    +
    + +
    + +
    + + + + + +
    +
    diff --git a/administrator/components/com_modules/views/positions/view.html.php b/administrator/components/com_modules/views/positions/view.html.php new file mode 100644 index 0000000..a013e2b --- /dev/null +++ b/administrator/components/com_modules/views/positions/view.html.php @@ -0,0 +1,43 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + parent::display($tpl); + } +} diff --git a/administrator/components/com_modules/views/preview/index.html b/administrator/components/com_modules/views/preview/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/views/preview/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/views/preview/tmpl/default.php b/administrator/components/com_modules/views/preview/tmpl/default.php new file mode 100644 index 0000000..c45cbb7 --- /dev/null +++ b/administrator/components/com_modules/views/preview/tmpl/default.php @@ -0,0 +1,29 @@ + + + + + + + + + + + +
    + +
    diff --git a/administrator/components/com_modules/views/preview/tmpl/index.html b/administrator/components/com_modules/views/preview/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/views/preview/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/views/preview/view.html.php b/administrator/components/com_modules/views/preview/view.html.php new file mode 100644 index 0000000..97fa4b9 --- /dev/null +++ b/administrator/components/com_modules/views/preview/view.html.php @@ -0,0 +1,29 @@ +get('editor'); + + $this->editor = JEditor::getInstance($editor); + + parent::display($tpl); + } +} diff --git a/administrator/components/com_modules/views/select/index.html b/administrator/components/com_modules/views/select/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/views/select/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/views/select/tmpl/default.php b/administrator/components/com_modules/views/select/tmpl/default.php new file mode 100644 index 0000000..0cebee9 --- /dev/null +++ b/administrator/components/com_modules/views/select/tmpl/default.php @@ -0,0 +1,46 @@ + + +

    +
      +items as &$item) : ?> + extension_id; + $name = $this->escape($item->name); + $desc = JHTML::_('string.truncate', ($this->escape($item->desc)), 200); + $short_desc = JHTML::_('string.truncate', ($this->escape($item->desc)), 90); + ?> + direction != "rtl") : ?> +
    • + + + + +
    • + +
    • + + + + +
    • + + +
    +
    diff --git a/administrator/components/com_modules/views/select/tmpl/index.html b/administrator/components/com_modules/views/select/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_modules/views/select/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_modules/views/select/view.html.php b/administrator/components/com_modules/views/select/view.html.php new file mode 100644 index 0000000..d4a4573 --- /dev/null +++ b/administrator/components/com_modules/views/select/view.html.php @@ -0,0 +1,67 @@ +get('State'); + $items = $this->get('Items'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->state = &$state; + $this->items = &$items; + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 3.0 + */ + protected function addToolbar() + { + // Add page title + JToolbarHelper::title(JText::_('COM_MODULES_MANAGER_MODULES'), 'module.png'); + + // Get the toolbar object instance + $bar = JToolBar::getInstance('toolbar'); + + // Cancel + $title = JText::_('JTOOLBAR_CANCEL'); + $dhtml = ""; + $bar->appendButton('Custom', $dhtml, 'new'); + } +} diff --git a/administrator/components/com_newsfeeds/access.xml b/administrator/components/com_newsfeeds/access.xml new file mode 100644 index 0000000..0020f94 --- /dev/null +++ b/administrator/components/com_newsfeeds/access.xml @@ -0,0 +1,19 @@ + + +
    + + + + + + + +
    +
    + + + + + +
    +
    \ No newline at end of file diff --git a/administrator/components/com_newsfeeds/config.xml b/administrator/components/com_newsfeeds/config.xml new file mode 100644 index 0000000..723e4a0 --- /dev/null +++ b/administrator/components/com_newsfeeds/config.xml @@ -0,0 +1,381 @@ + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    +
    diff --git a/administrator/components/com_newsfeeds/controller.php b/administrator/components/com_newsfeeds/controller.php new file mode 100644 index 0000000..9c122ea --- /dev/null +++ b/administrator/components/com_newsfeeds/controller.php @@ -0,0 +1,51 @@ +input->get('view', 'newsfeeds'); + $layout = $this->input->get('layout', 'default'); + $id = $this->input->getInt('id'); + + // Check for edit form. + if ($view == 'newsfeed' && $layout == 'edit' && !$this->checkEditId('com_newsfeeds.edit.newsfeed', $id)) + { + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_newsfeeds&view=newsfeeds', false)); + + return false; + } + + parent::display(); + } +} diff --git a/administrator/components/com_newsfeeds/controllers/index.html b/administrator/components/com_newsfeeds/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/controllers/newsfeed.php b/administrator/components/com_newsfeeds/controllers/newsfeed.php new file mode 100644 index 0000000..afff6be --- /dev/null +++ b/administrator/components/com_newsfeeds/controllers/newsfeed.php @@ -0,0 +1,122 @@ +input->getInt('filter_category_id'), 'int'); + $allow = null; + + if ($categoryId) + { + // If the category has been passed in the URL check it. + $allow = $user->authorise('core.create', $this->option . '.category.' . $categoryId); + } + + if ($allow === null) + { + // In the absence of better information, revert to the component permissions. + return parent::allowAdd($data); + } + else + { + return $allow; + } + } + + /** + * Method to check if you can edit a record. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowEdit($data = array(), $key = 'id') + { + $user = JFactory::getUser(); + $recordId = (int) isset($data[$key]) ? $data[$key] : 0; + $categoryId = 0; + + if ($recordId) + { + $categoryId = (int) $this->getModel()->getItem($recordId)->catid; + } + + if ($categoryId) + { + // The category has been set. Check the category permissions. + return $user->authorise('core.edit', $this->option . '.category.' . $categoryId); + } + else + { + // Since there is no asset tracking, revert to the component permissions. + return parent::allowEdit($data, $key); + } + } + + /** + * Method to run batch operations. + * + * @param object $model The model. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 2.5 + */ + public function batch($model = null) + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Set the model + $model = $this->getModel('Newsfeed', '', array()); + + // Preset the redirect + $this->setRedirect(JRoute::_('index.php?option=com_newsfeeds&view=newsfeeds' . $this->getRedirectToListAppend(), false)); + + return parent::batch($model); + } + + /** + * Function that allows child controller access to model data after the data has been saved. + * + * @param JModelLegacy $model The data model object. + * @param array $validData The validated data. + * + * @return void + * + * @since 3.1 + */ + protected function postSaveHook(JModelLegacy $model, $validData = array()) + { + + } +} diff --git a/administrator/components/com_newsfeeds/controllers/newsfeeds.php b/administrator/components/com_newsfeeds/controllers/newsfeeds.php new file mode 100644 index 0000000..6c0a35d --- /dev/null +++ b/administrator/components/com_newsfeeds/controllers/newsfeeds.php @@ -0,0 +1,33 @@ + true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } + + protected function postDeleteHook(JModelLegacy $model, $ids = null) + { + } +} diff --git a/administrator/components/com_newsfeeds/helpers/html/index.html b/administrator/components/com_newsfeeds/helpers/html/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/helpers/html/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/helpers/html/newsfeed.php b/administrator/components/com_newsfeeds/helpers/html/newsfeed.php new file mode 100644 index 0000000..24e120d --- /dev/null +++ b/administrator/components/com_newsfeeds/helpers/html/newsfeed.php @@ -0,0 +1,91 @@ + $associated) + { + $associations[$tag] = (int) $associated->id; + } + + // Get the associated newsfeed items + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('c.id, c.name as title') + ->select('l.sef as lang_sef') + ->from('#__newsfeeds as c') + ->select('cat.title as category_title') + ->join('LEFT', '#__categories as cat ON cat.id=c.catid') + ->where('c.id IN (' . implode(',', array_values($associations)) . ')') + ->join('LEFT', '#__languages as l ON c.language=l.lang_code') + ->select('l.image') + ->select('l.title as language_title'); + $db->setQuery($query); + + try + { + $items = $db->loadObjectList('id'); + } + catch (RuntimeException $e) + { + throw new Exception($e->getMessage(), 500); + } + + if ($items) + { + foreach ($items as &$item) + { + $text = strtoupper($item->lang_sef); + $url = JRoute::_('index.php?option=com_newsfeeds&task=newsfeed.edit&id=' . (int) $item->id); + $tooltipParts = array( + JHtml::_('image', 'mod_languages/' . $item->image . '.gif', + $item->language_title, + array('title' => $item->language_title), + true + ), + $item->title, + '(' . $item->category_title . ')' + ); + $item->link = JHtml::_('tooltip', implode(' ', $tooltipParts), null, null, $text, $url, null, 'hasTooltip label label-association label-' . $item->lang_sef); + } + } + + $html = JLayoutHelper::render('joomla.content.associations', $items); + } + + return $html; + } +} diff --git a/administrator/components/com_newsfeeds/helpers/index.html b/administrator/components/com_newsfeeds/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/helpers/newsfeeds.php b/administrator/components/com_newsfeeds/helpers/newsfeeds.php new file mode 100644 index 0000000..8d5ec1e --- /dev/null +++ b/administrator/components/com_newsfeeds/helpers/newsfeeds.php @@ -0,0 +1,80 @@ +set($action->name, $user->authorise($action->name, $assetName)); + } + + return $result; + } +} diff --git a/administrator/components/com_newsfeeds/index.html b/administrator/components/com_newsfeeds/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/models/fields/index.html b/administrator/components/com_newsfeeds/models/fields/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/models/fields/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/models/fields/modal/index.html b/administrator/components/com_newsfeeds/models/fields/modal/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/models/fields/modal/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/models/fields/modal/newsfeed.php b/administrator/components/com_newsfeeds/models/fields/modal/newsfeed.php new file mode 100644 index 0000000..a60f5ec --- /dev/null +++ b/administrator/components/com_newsfeeds/models/fields/modal/newsfeed.php @@ -0,0 +1,163 @@ +element['edit'] == 'true') ? true : false; + $allowClear = ((string) $this->element['clear'] != 'false') ? true : false; + + // Load language + JFactory::getLanguage()->load('com_newsfeeds', JPATH_ADMINISTRATOR); + + // Load the javascript + JHtml::_('behavior.framework'); + JHtml::_('behavior.modal', 'a.modal'); + JHtml::_('bootstrap.tooltip'); + + // Build the script. + $script = array(); + + // Select button script + $script[] = ' function jSelectNewsfeed_'.$this->id.'(id, name, object) {'; + $script[] = ' document.id("'.$this->id.'_id").value = id;'; + $script[] = ' document.id("'.$this->id.'_name").value = name;'; + + if ($allowEdit) + { + $script[] = ' jQuery("#'.$this->id.'_edit").removeClass("hidden");'; + } + + if ($allowClear) + { + $script[] = ' jQuery("#'.$this->id.'_clear").removeClass("hidden");'; + } + + $script[] = ' SqueezeBox.close();'; + $script[] = ' }'; + + // Clear button script + static $scriptClear; + + if ($allowClear && !$scriptClear) + { + $scriptClear = true; + + $script[] = ' function jClearNewsfeed(id) {'; + $script[] = ' document.getElementById(id + "_id").value = "";'; + $script[] = ' document.getElementById(id + "_name").value = "'.htmlspecialchars(JText::_('COM_NEWSFEEDS_SELECT_A_FEED', true), ENT_COMPAT, 'UTF-8').'";'; + $script[] = ' jQuery("#"+id + "_clear").addClass("hidden");'; + $script[] = ' if (document.getElementById(id + "_edit")) {'; + $script[] = ' jQuery("#"+id + "_edit").addClass("hidden");'; + $script[] = ' }'; + $script[] = ' return false;'; + $script[] = ' }'; + } + + // Add the script to the document head. + JFactory::getDocument()->addScriptDeclaration(implode("\n", $script)); + + // Setup variables for display. + $html = array(); + $link = 'index.php?option=com_newsfeeds&view=newsfeeds&layout=modal&tmpl=component&function=jSelectNewsfeed_'.$this->id; + + if (isset($this->element['language'])) + { + $link .= '&forcedLanguage='.$this->element['language']; + } + + // Get the title of the linked chart + $db = JFactory::getDbo(); + $db->setQuery( + 'SELECT name' . + ' FROM #__newsfeeds' . + ' WHERE id = '.(int) $this->value + ); + + try + { + $title = $db->loadResult(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage); + } + + if (empty($title)) + { + $title = JText::_('COM_NEWSFEEDS_SELECT_A_FEED'); + } + $title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); + + // The active newsfeed id field. + if (0 == (int) $this->value) + { + $value = ''; + } + else + { + $value = (int) $this->value; + } + + // The current newsfeed display field. + $html[] = ''; + $html[] = ''; + $html[] = ' '.JText::_('JSELECT').''; + + // Edit newsfeed button + if ($allowEdit) + { + $html[] = ' ' . JText::_('JACTION_EDIT') . ''; + } + + // Clear newsfeed button + if ($allowClear) + { + $html[] = ''; + } + + $html[] = ''; + + // class='required' for client side validation + $class = ''; + + if ($this->required) + { + $class = ' class="required modal-value"'; + } + + $html[] = ''; + + return implode("\n", $html); + } +} diff --git a/administrator/components/com_newsfeeds/models/fields/newsfeeds.php b/administrator/components/com_newsfeeds/models/fields/newsfeeds.php new file mode 100644 index 0000000..fb7cc32 --- /dev/null +++ b/administrator/components/com_newsfeeds/models/fields/newsfeeds.php @@ -0,0 +1,64 @@ +getQuery(true) + ->select('id As value, name As text') + ->from('#__newsfeeds AS a') + ->order('a.name'); + + // Get the options. + $db->setQuery($query); + + try + { + $options = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $db->getMessage()); + } + + // Merge any additional options in the XML definition. + $options = array_merge(parent::getOptions(), $options); + + return $options; + } +} diff --git a/administrator/components/com_newsfeeds/models/fields/ordering.php b/administrator/components/com_newsfeeds/models/fields/ordering.php new file mode 100644 index 0000000..2b4fe5e --- /dev/null +++ b/administrator/components/com_newsfeeds/models/fields/ordering.php @@ -0,0 +1,71 @@ +element['class'] ? ' class="'.(string) $this->element['class'].'"' : ''; + $attr .= ((string) $this->element['disabled'] == 'true') ? ' disabled="disabled"' : ''; + $attr .= $this->element['size'] ? ' size="'.(int) $this->element['size'].'"' : ''; + + // Initialize JavaScript field attributes. + $attr .= $this->element['onchange'] ? ' onchange="'.(string) $this->element['onchange'].'"' : ''; + + // Get some field values from the form. + $newsfeedId = (int) $this->form->getValue('id'); + $categoryId = (int) $this->form->getValue('catid'); + + // Build the query for the ordering list. + $query = 'SELECT ordering AS value, name AS text' . + ' FROM #__newsfeeds' . + ' WHERE catid = ' . (int) $categoryId . + ' ORDER BY ordering'; + + // Create a read-only list (no name) with a hidden input to store the value. + if ((string) $this->element['readonly'] == 'true') + { + $html[] = JHtml::_('list.ordering', '', $query, trim($attr), $this->value, $newsfeedId ? 0 : 1); + $html[] = ''; + } + // Create a regular list. + else { + $html[] = JHtml::_('list.ordering', $this->name, $query, trim($attr), $this->value, $newsfeedId ? 0 : 1); + } + + return implode($html); + } +} diff --git a/administrator/components/com_newsfeeds/models/forms/index.html b/administrator/components/com_newsfeeds/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/models/forms/newsfeed.xml b/administrator/components/com_newsfeeds/models/forms/newsfeed.xml new file mode 100644 index 0000000..b07b76c --- /dev/null +++ b/administrator/components/com_newsfeeds/models/forms/newsfeed.xml @@ -0,0 +1,290 @@ + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    + + + + + + + + + + +
    + + + +
    +
    diff --git a/administrator/components/com_newsfeeds/models/index.html b/administrator/components/com_newsfeeds/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/models/newsfeed.php b/administrator/components/com_newsfeeds/models/newsfeed.php new file mode 100644 index 0000000..a128fc3 --- /dev/null +++ b/administrator/components/com_newsfeeds/models/newsfeed.php @@ -0,0 +1,577 @@ +getTable(); + $i = 0; + + // Check that the category exists + if ($categoryId) + { + $categoryTable = JTable::getInstance('Category'); + if (!$categoryTable->load($categoryId)) + { + if ($error = $categoryTable->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND')); + return false; + } + } + } + + if (empty($categoryId)) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND')); + return false; + } + + // Check that the user has create permission for the component + $user = JFactory::getUser(); + if (!$user->authorise('core.create', 'com_newsfeeds.category.' . $categoryId)) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE')); + return false; + } + + // Parent exists so we let's proceed + while (!empty($pks)) + { + // Pop the first ID off the stack + $pk = array_shift($pks); + + $table->reset(); + + // Check that the row actually exists + if (!$table->load($pk)) + { + if ($error = $table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Not fatal error + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + } + + // Alter the title & alias + $data = $this->generateNewTitle($categoryId, $table->alias, $table->name); + $table->name = $data['0']; + $table->alias = $data['1']; + + // Reset the ID because we are making a copy + $table->id = 0; + + // New category ID + $table->catid = $categoryId; + + // TODO: Deal with ordering? + //$table->ordering = 1; + + // Check the row. + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // Store the row. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Get the new item ID + $newId = $table->get('id'); + + // Add the new ID to the array + $newIds[$i] = $newId; + $i++; + } + + // Clean the cache + $this->cleanCache(); + + return $newIds; + } + + /** + * Method to test whether a record can be deleted. + * + * @param object A record object. + * @return boolean True if allowed to delete the record. Defaults to the permission set in the component. + * @since 1.6 + */ + protected function canDelete($record) + { + if (!empty($record->id)) + { + if ($record->published != -2) + { + return; + } + $user = JFactory::getUser(); + + if (!empty($record->catid)) + { + return $user->authorise('core.delete', 'com_newsfeed.category.' . (int) $record->catid); + } + else + { + return parent::canDelete($record); + } + } + } + + /** + * Method to test whether a record can have its state changed. + * + * @param object A record object. + * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. + * @since 1.6 + */ + protected function canEditState($record) + { + $user = JFactory::getUser(); + + if (!empty($record->catid)) + { + return $user->authorise('core.edit.state', 'com_newsfeeds.category.' . (int) $record->catid); + } + else + { + return parent::canEditState($record); + } + } + + /** + * Returns a Table object, always creating it. + * + * @param type The table type to instantiate + * @param string A prefix for the table class name. Optional. + * @param array Configuration array for model. Optional. + * @return JTable A database object + */ + public function getTable($type = 'Newsfeed', $prefix = 'NewsfeedsTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Method to get the record form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * @return JForm A JForm object on success, false on failure + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + // Get the form. + $form = $this->loadForm('com_newsfeeds.newsfeed', 'newsfeed', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + // Determine correct permissions to check. + if ($this->getState('newsfeed.id')) + { + // Existing record. Can only edit in selected categories. + $form->setFieldAttribute('catid', 'action', 'core.edit'); + } + else + { + // New record. Can only create in selected categories. + $form->setFieldAttribute('catid', 'action', 'core.create'); + } + + // Modify the form based on access controls. + if (!$this->canEditState((object) $data)) + { + // Disable fields for display. + $form->setFieldAttribute('ordering', 'disabled', 'true'); + $form->setFieldAttribute('published', 'disabled', 'true'); + $form->setFieldAttribute('publish_up', 'disabled', 'true'); + $form->setFieldAttribute('publish_down', 'disabled', 'true'); + + // Disable fields while saving. + // The controller has already verified this is a record you can edit. + $form->setFieldAttribute('ordering', 'filter', 'unset'); + $form->setFieldAttribute('published', 'filter', 'unset'); + $form->setFieldAttribute('publish_up', 'filter', 'unset'); + $form->setFieldAttribute('publish_down', 'filter', 'unset'); + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_newsfeeds.edit.newsfeed.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + + // Prime some default values. + if ($this->getState('newsfeed.id') == 0) + { + $app = JFactory::getApplication(); + $data->set('catid', $app->input->get('catid', $app->getUserState('com_newsfeeds.newsfeeds.filter.category_id'), 'int')); + } + } + + $this->preprocessData('com_newsfeeds.newsfeed', $data); + + return $data; + } + + /** + * Method to save the form data. + * + * @param array The form data. + * + * @return boolean True on success. + * @since 3.0 + */ + public function save($data) + { + $app = JFactory::getApplication(); + + // Alter the title for save as copy + if ($app->input->get('task') == 'save2copy') + { + list($name, $alias) = $this->generateNewTitle($data['catid'], $data['alias'], $data['name']); + $data['name'] = $name; + $data['alias'] = $alias; + $data['published'] = 0; + } + + if (parent::save($data)) + { + + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $id = (int) $this->getState($this->getName() . '.id'); + $item = $this->getItem($id); + + // Adding self to the association + $associations = $data['associations']; + + foreach ($associations as $tag => $id) + { + if (empty($id)) + { + unset($associations[$tag]); + } + } + + // Detecting all item menus + $all_language = $item->language == '*'; + + if ($all_language && !empty($associations)) + { + JError::raiseNotice(403, JText::_('COM_NEWSFEEDS_ERROR_ALL_LANGUAGE_ASSOCIATED')); + } + + $associations[$item->language] = $item->id; + + // Deleting old association for these items + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->delete('#__associations') + ->where($db->quoteName('context') . ' = ' . $db->quote('com_newsfeeds.item')) + ->where($db->quoteName('id') . ' IN (' . implode(',', $associations) . ')'); + $db->setQuery($query); + $db->execute(); + + if ($error = $db->getErrorMsg()) + { + $this->setError($error); + return false; + } + + if (!$all_language && count($associations)) + { + // Adding new association for these items + $key = md5(json_encode($associations)); + $query->clear() + ->insert('#__associations'); + + foreach ($associations as $id) + { + $query->values($id . ',' . $db->quote('com_newsfeeds.item') . ',' . $db->quote($key)); + } + + $db->setQuery($query); + $db->execute(); + + if ($error = $db->getErrorMsg()) + { + $this->setError($error); + return false; + } + } + } + + return true; + } + + return false; + } + + /** + * Method to get a single record. + * + * @param integer The id of the primary key. + * + * @return mixed Object on success, false on failure. + * @since 1.6 + */ + public function getItem($pk = null) + { + if ($item = parent::getItem($pk)) + { + // Convert the params field to an array. + $registry = new JRegistry; + $registry->loadString($item->metadata); + $item->metadata = $registry->toArray(); + + // Convert the images field to an array. + $registry = new JRegistry; + $registry->loadString($item->images); + $item->images = $registry->toArray(); + } + + // Load associated newsfeeds items + $app = JFactory::getApplication(); + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + + if ($assoc) + { + $item->associations = array(); + + if ($item->id != null) + { + $associations = JLanguageAssociations::getAssociations('com_newsfeeds', '#__newsfeeds', 'com_newsfeeds.item', $item->id); + + foreach ($associations as $tag => $association) + { + $item->associations[$tag] = $association->id; + } + } + } + if (!empty($item->id)) + { + $item->tags = new JHelperTags; + $item->tags->getTagIds($item->id, 'com_newsfeeds.newsfeed'); + $item->metadata['tags'] = $item->tags; + } + + return $item; + } + + /** + * Prepare and sanitise the table prior to saving. + */ + protected function prepareTable($table) + { + $date = JFactory::getDate(); + $user = JFactory::getUser(); + + $table->name = htmlspecialchars_decode($table->name, ENT_QUOTES); + $table->alias = JApplication::stringURLSafe($table->alias); + + if (empty($table->alias)) + { + $table->alias = JApplication::stringURLSafe($table->name); + } + + if (empty($table->id)) + { + // Set the values + $table->created = $date->toSql(); + + // Set ordering to the last item if not set + if (empty($table->ordering)) + { + $db = JFactory::getDbo(); + $db->setQuery('SELECT MAX(ordering) FROM #__newsfeeds'); + $max = $db->loadResult(); + + $table->ordering = $max + 1; + } + } + else + { + // Set the values + $table->modified = $date->toSql(); + $table->modified_by = $user->get('id'); + } + + // Increment the content version number. + $table->version++; + } + + /** + * Method to change the published state of one or more records. + * + * @param array $pks A list of the primary keys to change. + * @param integer $value The value of the published state. + * + * @return boolean True on success. + * @since 1.6 + */ + public function publish(&$pks, $value = 1) + { + $result = parent::publish($pks, $value); + + // Clean extra cache for newsfeeds + $this->cleanCache('feed_parser'); + + return $result; + } + + /** + * A protected method to get a set of ordering conditions. + * + * @param object A record object. + * @return array An array of conditions to add to add to ordering queries. + * @since 1.6 + */ + protected function getReorderConditions($table) + { + $condition = array(); + $condition[] = 'catid = ' . (int) $table->catid; + return $condition; + } + + protected function preprocessForm(JForm $form, $data, $group = 'content') + { + // Association newsfeeds items + $app = JFactory::getApplication(); + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $languages = JLanguageHelper::getLanguages('lang_code'); + + // force to array (perhaps move to $this->loadFormData()) + $data = (array) $data; + + $addform = new SimpleXMLElement('
    '); + $fields = $addform->addChild('fields'); + $fields->addAttribute('name', 'associations'); + $fieldset = $fields->addChild('fieldset'); + $fieldset->addAttribute('name', 'item_associations'); + $fieldset->addAttribute('description', 'COM_NEWSFEEDS_ITEM_ASSOCIATIONS_FIELDSET_DESC'); + $add = false; + foreach ($languages as $tag => $language) + { + if (empty($data['language']) || $tag != $data['language']) + { + $add = true; + $field = $fieldset->addChild('field'); + $field->addAttribute('name', $tag); + $field->addAttribute('type', 'modal_newsfeed'); + $field->addAttribute('language', $tag); + $field->addAttribute('label', $language->title); + $field->addAttribute('translate_label', 'false'); + $field->addAttribute('edit', 'true'); + $field->addAttribute('clear', 'true'); + } + } + if ($add) + { + $form->load($addform, false); + } + } + + parent::preprocessForm($form, $data, $group); + } + + /** + * Method to change the title & alias. + * + * @param integer $parent_id The id of the parent. + * @param string $alias The alias. + * @param string $title The title. + * + * @return array Contains the modified title and alias. + * + * @since 3.1 + */ + protected function generateNewTitle($category_id, $alias, $name) + { + // Alter the title & alias + $table = $this->getTable(); + while ($table->load(array('alias' => $alias, 'catid' => $category_id))) + { + if ($name == $table->name) + { + $name = JString::increment($name); + } + $alias = JString::increment($alias, 'dash'); + } + + return array($name, $alias); + } +} diff --git a/administrator/components/com_newsfeeds/models/newsfeeds.php b/administrator/components/com_newsfeeds/models/newsfeeds.php new file mode 100644 index 0000000..d801f04 --- /dev/null +++ b/administrator/components/com_newsfeeds/models/newsfeeds.php @@ -0,0 +1,262 @@ +item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $config['filter_fields'][] = 'association'; + } + } + + parent::__construct($config); + } + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @param string $ordering An optional ordering field. + * @param string $direction An optional direction (asc|desc). + * + * @return void + * + * @since 1.6 + */ + protected function populateState($ordering = null, $direction = null) + { + $app = JFactory::getApplication('administrator'); + + // Load the filter state. + $search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $accessId = $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access', null, 'int'); + $this->setState('filter.access', $accessId); + + $state = $this->getUserStateFromRequest($this->context . '.filter.published', 'filter_published', '', 'string'); + $this->setState('filter.published', $state); + + $categoryId = $this->getUserStateFromRequest($this->context . '.filter.category_id', 'filter_category_id', null); + $this->setState('filter.category_id', $categoryId); + + $language = $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', ''); + $this->setState('filter.language', $language); + + // force a language + $forcedLanguage = $app->input->get('forcedLanguage'); + if (!empty($forcedLanguage)) + { + $this->setState('filter.language', $forcedLanguage); + $this->setState('filter.forcedLanguage', $forcedLanguage); + } + + $tag = $this->getUserStateFromRequest($this->context . '.filter.tag', 'filter_tag', ''); + $this->setState('filter.tag', $tag); + + // Load the parameters. + $params = JComponentHelper::getParams('com_newsfeeds'); + $this->setState('params', $params); + + // List state information. + parent::populateState('a.name', 'asc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string A prefix for the store id. + * + * @return string A store id. + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.access'); + $id .= ':' . $this->getState('filter.published'); + $id .= ':' . $this->getState('filter.category_id'); + $id .= ':' . $this->getState('filter.language'); + + return parent::getStoreId($id); + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + $user = JFactory::getUser(); + $app = JFactory::getApplication(); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.id, a.name, a.alias, a.checked_out, a.checked_out_time, a.catid,' . + ' a.numarticles, a.cache_time,' . + ' a.published, a.access, a.ordering, a.language, a.publish_up, a.publish_down' + ) + ); + $query->from($db->quoteName('#__newsfeeds') . ' AS a'); + + // Join over the language + $query->select('l.title AS language_title') + ->join('LEFT', $db->quoteName('#__languages') . ' AS l ON l.lang_code = a.language'); + + // Join over the users for the checked out user. + $query->select('uc.name AS editor') + ->join('LEFT', '#__users AS uc ON uc.id=a.checked_out'); + + // Join over the asset groups. + $query->select('ag.title AS access_level') + ->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access'); + + // Join over the categories. + $query->select('c.title AS category_title') + ->join('LEFT', '#__categories AS c ON c.id = a.catid'); + + // Join over the associations. + $assoc = isset($app->item_associations) ? $app->item_associations : 0; + if ($assoc) + { + $query->select('COUNT(asso2.id)>1 as association') + ->join('LEFT', '#__associations AS asso ON asso.id = a.id AND asso.context=' . $db->quote('com_newsfeeds.item')) + ->join('LEFT', '#__associations AS asso2 ON asso2.key = asso.key') + ->group('a.id'); + } + + // Filter by access level. + if ($access = $this->getState('filter.access')) + { + $query->where('a.access = ' . (int) $access); + } + + // Implement View Level Access + if (!$user->authorise('core.admin')) + { + $groups = implode(',', $user->getAuthorisedViewLevels()); + $query->where('a.access IN (' . $groups . ')'); + } + + // Filter by published state. + $published = $this->getState('filter.published'); + if (is_numeric($published)) + { + $query->where('a.published = ' . (int) $published); + } + elseif ($published === '') + { + $query->where('(a.published IN (0, 1))'); + } + + // Filter by category. + $categoryId = $this->getState('filter.category_id'); + if (is_numeric($categoryId)) + { + $query->where('a.catid = ' . (int) $categoryId); + } + + // Filter by search in title + $search = $this->getState('filter.search'); + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + else + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('(a.name LIKE ' . $search . ' OR a.alias LIKE ' . $search . ')'); + } + } + + // Filter on the language. + if ($language = $this->getState('filter.language')) + { + $query->where('a.language = ' . $db->quote($language)); + } + + // Filter by a single tag. + $tagId = $this->getState('filter.tag'); + if (is_numeric($tagId)) + { + $query->where($db->quoteName('tagmap.tag_id') . ' = ' . (int) $tagId) + ->join( + 'LEFT', $db->quoteName('#__contentitem_tag_map', 'tagmap') + . ' ON ' . $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id') + . ' AND ' . $db->quoteName('tagmap.type_alias') . ' = ' . $db->quote('com_newsfeeds.newsfeed') + ); + } + + // Add the list ordering clause. + $orderCol = $this->state->get('list.ordering'); + $orderDirn = $this->state->get('list.direction'); + if ($orderCol == 'a.ordering' || $orderCol == 'category_title') + { + $orderCol = 'c.title ' . $orderDirn . ', a.ordering'; + } + $query->order($db->escape($orderCol . ' ' . $orderDirn)); + + //echo nl2br(str_replace('#__','jos_',$query)); + return $query; + } +} diff --git a/administrator/components/com_newsfeeds/newsfeeds.php b/administrator/components/com_newsfeeds/newsfeeds.php new file mode 100644 index 0000000..fb0184a --- /dev/null +++ b/administrator/components/com_newsfeeds/newsfeeds.php @@ -0,0 +1,19 @@ +authorise('core.manage', 'com_newsfeeds')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$controller = JControllerLegacy::getInstance('Newsfeeds'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_newsfeeds/newsfeeds.xml b/administrator/components/com_newsfeeds/newsfeeds.xml new file mode 100644 index 0000000..e925adf --- /dev/null +++ b/administrator/components/com_newsfeeds/newsfeeds.xml @@ -0,0 +1,68 @@ + + + com_newsfeeds + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_NEWSFEEDS_XML_DESCRIPTION + + + + sql/install.mysql.utf8.sql + + + + + sql/uninstall.mysql.utf8.sql + + + + + controller.php + index.html + metadata.xml + newsfeeds.php + router.php + helpers + models + views + + + language/en-GB.com_newsfeeds.ini + + + com_newsfeeds + + + com_newsfeeds_feeds + com_newsfeeds_categories + + + access.xml + config.xml + controller.php + index.html + newsfeeds.php + controllers + elements + helpers + models + tables + views + + + language/en-GB.com_newsfeeds.ini + language/en-GB.com_newsfeeds.sys.ini + + + + diff --git a/administrator/components/com_newsfeeds/sql/index.html b/administrator/components/com_newsfeeds/sql/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/sql/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/sql/install.mysql.utf8.sql b/administrator/components/com_newsfeeds/sql/install.mysql.utf8.sql new file mode 100644 index 0000000..6c53324 --- /dev/null +++ b/administrator/components/com_newsfeeds/sql/install.mysql.utf8.sql @@ -0,0 +1,40 @@ +CREATE TABLE `#__newsfeeds` ( + `catid` integer NOT NULL default '0', + `id` integer(10) UNSIGNED NOT NULL auto_increment, + `name` varchar(100) NOT NULL DEFAULT '', + `alias` varchar(100) NOT NULL default '', + `link` varchar(200) NOT NULL DEFAULT '', + `filename` varchar(200) default NULL, + `published` tinyint(1) NOT NULL default '0', + `numarticles` integer unsigned NOT NULL default '1', + `cache_time` integer unsigned NOT NULL default '3600', + `checked_out` integer(10) unsigned NOT NULL default '0', + `checked_out_time` datetime NOT NULL default '0000-00-00 00:00:00', + `ordering` integer NOT NULL default '0', + `rtl` tinyint(4) NOT NULL default '0', + `access` tinyint UNSIGNED NOT NULL DEFAULT '0', + `language` char(7) NOT NULL DEFAULT '', + `params` text NOT NULL, + `created` datetime NOT NULL default '0000-00-00 00:00:00', + `created_by` int(10) unsigned NOT NULL default '0', + `created_by_alias` varchar(255) NOT NULL default '', + `modified` datetime NOT NULL default '0000-00-00 00:00:00', + `modified_by` int(10) unsigned NOT NULL default '0', + `metakey` text NOT NULL, + `metadesc` text NOT NULL, + `metadata` text NOT NULL, + `xreference` varchar(50) NOT NULL COMMENT 'A reference to enable linkages to external data sets.', + `publish_up` datetime NOT NULL default '0000-00-00 00:00:00', + `publish_down` datetime NOT NULL default '0000-00-00 00:00:00', + + PRIMARY KEY (`id`), + KEY `idx_access` (`access`), + KEY `idx_checkout` (`checked_out`), + KEY `idx_state` (`published`), + KEY `idx_catid` (`catid`), + KEY `idx_createdby` (`created_by`), + KEY `idx_language` (`language`), + KEY `idx_xreference` (`xreference`) + +) DEFAULT CHARSET=utf8; + diff --git a/administrator/components/com_newsfeeds/sql/uninstall.mysql.utf8.sql b/administrator/components/com_newsfeeds/sql/uninstall.mysql.utf8.sql new file mode 100644 index 0000000..f29779a --- /dev/null +++ b/administrator/components/com_newsfeeds/sql/uninstall.mysql.utf8.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS `#__newsfeeds`; + diff --git a/administrator/components/com_newsfeeds/tables/index.html b/administrator/components/com_newsfeeds/tables/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/tables/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/tables/newsfeed.php b/administrator/components/com_newsfeeds/tables/newsfeed.php new file mode 100644 index 0000000..b48cf0f --- /dev/null +++ b/administrator/components/com_newsfeeds/tables/newsfeed.php @@ -0,0 +1,171 @@ +loadArray($array['params']); + $array['params'] = (string) $registry; + } + + if (isset($array['metadata']) && is_array($array['metadata'])) + { + $registry = new JRegistry; + $registry->loadArray($array['metadata']); + $array['metadata'] = (string) $registry; + } + + if (isset($array['images']) && is_array($array['images'])) + { + $registry = new JRegistry; + $registry->loadArray($array['images']); + $array['images'] = (string) $registry; + } + + return parent::bind($array, $ignore); + } + + /** + * Overloaded check method to ensure data integrity. + * + * @return boolean True on success. + */ + public function check() + { + // Check for valid name. + if (trim($this->name) == '') + { + $this->setError(JText::_('COM_NEWSFEEDS_WARNING_PROVIDE_VALID_NAME')); + return false; + } + + if (empty($this->alias)) + { + $this->alias = $this->name; + } + $this->alias = JApplication::stringURLSafe($this->alias); + if (trim(str_replace('-', '', $this->alias)) == '') + { + $this->alias = JFactory::getDate()->format("Y-m-d-H-i-s"); + } + + // Check the publish down date is not earlier than publish up. + if ((int) $this->publish_down > 0 && $this->publish_down < $this->publish_up) + { + $this->setError(JText::_('JGLOBAL_START_PUBLISH_AFTER_FINISH')); + return false; + } + + // clean up keywords -- eliminate extra spaces between phrases + // and cr (\r) and lf (\n) characters from string + if (!empty($this->metakey)) + { + // only process if not empty + $bad_characters = array("\n", "\r", "\"", "<", ">"); // array of characters to remove + $after_clean = JString::str_ireplace($bad_characters, "", $this->metakey); // remove bad characters + $keys = explode(',', $after_clean); // create array using commas as delimiter + $clean_keys = array(); + + foreach ($keys as $key) + { + if (trim($key)) { // ignore blank keywords + $clean_keys[] = trim($key); + } + } + $this->metakey = implode(", ", $clean_keys); // put array back together delimited by ", " + } + + // clean up description -- eliminate quotes and <> brackets + if (!empty($this->metadesc)) + { + // only process if not empty + $bad_characters = array("\"", "<", ">"); + $this->metadesc = JString::str_ireplace($bad_characters, "", $this->metadesc); + } + + return true; + } + + /** + * Overriden JTable::store to set modified data. + * + * @param boolean $updateNulls True to update fields even if they are null. + * + * @return boolean True on success. + * + * @since 1.6 + */ + public function store($updateNulls = false) + { + $date = JFactory::getDate(); + $user = JFactory::getUser(); + if ($this->id) + { + // Existing item + $this->modified = $date->toSql(); + $this->modified_by = $user->get('id'); + } + else + { + // New newsfeed. A feed created and created_by field can be set by the user, + // so we don't touch either of these if they are set. + if (!(int) $this->created) + { + $this->created = $date->toSql(); + } + if (empty($this->created_by)) + { + $this->created_by = $user->get('id'); + } + } + // Verify that the alias is unique + $table = JTable::getInstance('Newsfeed', 'NewsfeedsTable'); + if ($table->load(array('alias' => $this->alias, 'catid' => $this->catid)) && ($table->id != $this->id || $this->id == 0)) + { + $this->setError(JText::_('COM_NEWSFEEDS_ERROR_UNIQUE_ALIAS')); + return false; + } + + // Save links as punycode. + $this->link = JStringPunycode::urlToPunycode($this->link); + + return parent::store($updateNulls); + } +} diff --git a/administrator/components/com_newsfeeds/views/index.html b/administrator/components/com_newsfeeds/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/views/newsfeed/index.html b/administrator/components/com_newsfeeds/views/newsfeed/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/views/newsfeed/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/views/newsfeed/tmpl/edit.php b/administrator/components/com_newsfeeds/views/newsfeed/tmpl/edit.php new file mode 100644 index 0000000..387b1d9 --- /dev/null +++ b/administrator/components/com_newsfeeds/views/newsfeed/tmpl/edit.php @@ -0,0 +1,203 @@ +input; + +$assoc = isset($app->item_associations) ? $app->item_associations : 0; +?> + + + + + + +
    + +
    + +
    + 'details')); ?> + + item->id) ? JText::_('COM_NEWSFEEDS_NEW_NEWSFEED', true) : JText::sprintf('COM_NEWSFEEDS_EDIT_NEWSFEED', $this->item->id, true)); ?> +
    +
    form->getLabel('name'); ?>
    +
    form->getInput('name'); ?>
    +
    +
    +
    form->getLabel('link'); ?>
    +
    form->getInput('link'); ?>
    +
    +
    +
    form->getLabel('catid'); ?>
    +
    form->getInput('catid'); ?>
    +
    +
    +
    form->getLabel('description'); ?>
    +
    form->getInput('description'); ?>
    +
    + +
    +

    +
    +
    + form->getLabel('images'); ?> +
    +
    + form->getInput('images'); ?> +
    +
    + form->getGroup('images') as $field) : ?> +
    + hidden) : ?> +
    + label; ?> +
    + +
    + input; ?> +
    +
    + +
    + + + + +
    +
    form->getLabel('alias'); ?>
    +
    form->getInput('alias'); ?>
    +
    +
    +
    form->getLabel('id'); ?>
    +
    form->getInput('id'); ?>
    +
    +
    +
    form->getLabel('created_by'); ?>
    +
    form->getInput('created_by'); ?>
    +
    +
    +
    form->getLabel('created_by_alias'); ?>
    +
    form->getInput('created_by_alias'); ?>
    +
    +
    +
    form->getLabel('created'); ?>
    +
    form->getInput('created'); ?>
    +
    +
    +
    form->getLabel('publish_up'); ?>
    +
    form->getInput('publish_up'); ?>
    +
    +
    +
    form->getLabel('publish_down'); ?>
    +
    form->getInput('publish_down'); ?>
    +
    + + item->modified_by) : ?> +
    +
    form->getLabel('modified_by'); ?>
    +
    form->getInput('modified_by'); ?>
    +
    +
    +
    form->getLabel('modified'); ?>
    +
    form->getInput('modified'); ?>
    +
    + + + item->version) : ?> +
    +
    + form->getLabel('version'); ?> +
    +
    + form->getInput('version'); ?> +
    +
    + + + item->hits) : ?> +
    +
    + form->getLabel('hits'); ?> +
    +
    + form->getInput('hits'); ?> +
    +
    + + +
    +
    form->getLabel('ordering'); ?>
    +
    form->getInput('ordering'); ?>
    +
    +
    +
    form->getLabel('numarticles'); ?>
    +
    form->getInput('numarticles'); ?>
    +
    +
    +
    form->getLabel('cache_time'); ?>
    +
    form->getInput('cache_time'); ?>
    +
    +
    +
    form->getLabel('rtl'); ?>
    +
    form->getInput('rtl'); ?>
    +
    + + + form->getFieldsets('params'); ?> + $fieldSet) : ?> + + label, true)); ?> + loadTemplate('params'); ?> + + + + form->getFieldsets('metadata'); ?> + $fieldSet) : ?> + + label, true)); ?> + loadTemplate('metadata'); ?> + + + + + + loadTemplate('associations'); ?> + + + + +
    + + + +
    + + + + +
    +
    diff --git a/administrator/components/com_newsfeeds/views/newsfeed/tmpl/edit_associations.php b/administrator/components/com_newsfeeds/views/newsfeed/tmpl/edit_associations.php new file mode 100644 index 0000000..a0a4024 --- /dev/null +++ b/administrator/components/com_newsfeeds/views/newsfeed/tmpl/edit_associations.php @@ -0,0 +1,12 @@ +form->getFieldsets('params'); +foreach ($fieldSets as $name => $fieldSet) : + ?> +
    + description) && trim($fieldSet->description)) : + echo '

    '.$this->escape(JText::_($fieldSet->description)).'

    '; + endif; + ?> + form->getFieldset($name) as $field) : ?> +
    +
    label; ?>
    +
    input; ?>
    +
    + +
    + diff --git a/administrator/components/com_newsfeeds/views/newsfeed/tmpl/index.html b/administrator/components/com_newsfeeds/views/newsfeed/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/views/newsfeed/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/views/newsfeed/tmpl/modal.php b/administrator/components/com_newsfeeds/views/newsfeed/tmpl/modal.php new file mode 100644 index 0000000..d8af130 --- /dev/null +++ b/administrator/components/com_newsfeeds/views/newsfeed/tmpl/modal.php @@ -0,0 +1,214 @@ +input; + +$assoc = isset($app->item_associations) ? $app->item_associations : 0; +?> + +
    + +
    + + + +
    + +
    +
    + +
    + +
    + 'details')); ?> + + item->id) ? JText::_('COM_NEWSFEEDS_NEW_NEWSFEED', true) : JText::sprintf('COM_NEWSFEEDS_EDIT_NEWSFEED', $this->item->id, true)); ?> +
    +
    form->getLabel('name'); ?>
    +
    form->getInput('name'); ?>
    +
    +
    +
    form->getLabel('link'); ?>
    +
    form->getInput('link'); ?>
    +
    +
    +
    form->getLabel('catid'); ?>
    +
    form->getInput('catid'); ?>
    +
    +
    +
    form->getLabel('description'); ?>
    +
    form->getInput('description'); ?>
    +
    + +
    +

    +
    +
    + form->getLabel('images'); ?> +
    +
    + form->getInput('images'); ?> +
    +
    + form->getGroup('images') as $field) : ?> +
    + hidden) : ?> +
    + label; ?> +
    + +
    + input; ?> +
    +
    + +
    + + + + +
    +
    form->getLabel('alias'); ?>
    +
    form->getInput('alias'); ?>
    +
    +
    +
    form->getLabel('id'); ?>
    +
    form->getInput('id'); ?>
    +
    +
    +
    form->getLabel('created_by'); ?>
    +
    form->getInput('created_by'); ?>
    +
    +
    +
    form->getLabel('created_by_alias'); ?>
    +
    form->getInput('created_by_alias'); ?>
    +
    +
    +
    form->getLabel('created'); ?>
    +
    form->getInput('created'); ?>
    +
    +
    +
    form->getLabel('publish_up'); ?>
    +
    form->getInput('publish_up'); ?>
    +
    +
    +
    form->getLabel('publish_down'); ?>
    +
    form->getInput('publish_down'); ?>
    +
    + + item->modified_by) : ?> +
    +
    form->getLabel('modified_by'); ?>
    +
    form->getInput('modified_by'); ?>
    +
    +
    +
    form->getLabel('modified'); ?>
    +
    form->getInput('modified'); ?>
    +
    + + + item->version) : ?> +
    +
    + form->getLabel('version'); ?> +
    +
    + form->getInput('version'); ?> +
    +
    + + + item->hits) : ?> +
    +
    + form->getLabel('hits'); ?> +
    +
    + form->getInput('hits'); ?> +
    +
    + + +
    +
    form->getLabel('ordering'); ?>
    +
    form->getInput('ordering'); ?>
    +
    +
    +
    form->getLabel('numarticles'); ?>
    +
    form->getInput('numarticles'); ?>
    +
    +
    +
    form->getLabel('cache_time'); ?>
    +
    form->getInput('cache_time'); ?>
    +
    +
    +
    form->getLabel('rtl'); ?>
    +
    form->getInput('rtl'); ?>
    +
    + + + form->getFieldsets('params'); ?> + $fieldSet) : ?> + + label, true)); ?> + loadTemplate('params'); ?> + + + + form->getFieldsets('metadata'); ?> + $fieldSet) : ?> + + label, true)); ?> + loadTemplate('metadata'); ?> + + + + +
    + + + + + +
    + + + + +
    +
    +
    \ No newline at end of file diff --git a/administrator/components/com_newsfeeds/views/newsfeed/tmpl/modal_associations.php b/administrator/components/com_newsfeeds/views/newsfeed/tmpl/modal_associations.php new file mode 100644 index 0000000..a0a4024 --- /dev/null +++ b/administrator/components/com_newsfeeds/views/newsfeed/tmpl/modal_associations.php @@ -0,0 +1,12 @@ +form->getFieldsets('params'); +foreach ($fieldSets as $name => $fieldSet) : + ?> +
    + description) && trim($fieldSet->description)) : + echo '

    '.$this->escape(JText::_($fieldSet->description)).'

    '; + endif; + ?> + form->getFieldset($name) as $field) : ?> +
    +
    label; ?>
    +
    input; ?>
    +
    + +
    + diff --git a/administrator/components/com_newsfeeds/views/newsfeed/view.html.php b/administrator/components/com_newsfeeds/views/newsfeed/view.html.php new file mode 100644 index 0000000..9c2d71c --- /dev/null +++ b/administrator/components/com_newsfeeds/views/newsfeed/view.html.php @@ -0,0 +1,97 @@ +state = $this->get('State'); + $this->item = $this->get('Item'); + $this->form = $this->get('Form'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + if ($this->getLayout() == 'modal') + { + $this->form->setFieldAttribute('language', 'readonly', 'true'); + $this->form->setFieldAttribute('catid', 'readonly', 'true'); + } + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + JFactory::getApplication()->input->set('hidemainmenu', true); + + $user = JFactory::getUser(); + $isNew = ($this->item->id == 0); + $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $user->get('id')); + // Since we don't track these assets at the item level, use the category id. + $canDo = NewsfeedsHelper::getActions($this->item->catid, 0); + + JToolbarHelper::title(JText::_('COM_NEWSFEEDS_MANAGER_NEWSFEED'), 'newsfeeds.png'); + + // If not checked out, can save the item. + if (!$checkedOut && ($canDo->get('core.edit') || count($user->getAuthorisedCategories('com_newsfeeds', 'core.create')) > 0)) + { + JToolbarHelper::apply('newsfeed.apply'); + JToolbarHelper::save('newsfeed.save'); + } + if (!$checkedOut && count($user->getAuthorisedCategories('com_newsfeeds', 'core.create')) > 0){ + JToolbarHelper::save2new('newsfeed.save2new'); + } + // If an existing item, can save to a copy. + if (!$isNew && $canDo->get('core.create')) + { + JToolbarHelper::save2copy('newsfeed.save2copy'); + } + + if (empty($this->item->id)) + { + JToolbarHelper::cancel('newsfeed.cancel'); + } + else + { + JToolbarHelper::cancel('newsfeed.cancel', 'JTOOLBAR_CLOSE'); + } + + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_COMPONENTS_NEWSFEEDS_FEEDS_EDIT'); + } +} diff --git a/administrator/components/com_newsfeeds/views/newsfeeds/index.html b/administrator/components/com_newsfeeds/views/newsfeeds/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/views/newsfeeds/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/views/newsfeeds/tmpl/default.php b/administrator/components/com_newsfeeds/views/newsfeeds/tmpl/default.php new file mode 100644 index 0000000..6ce781a --- /dev/null +++ b/administrator/components/com_newsfeeds/views/newsfeeds/tmpl/default.php @@ -0,0 +1,263 @@ +get('id'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$archived = $this->state->get('filter.published') == 2 ? true : false; +$trashed = $this->state->get('filter.published') == -2 ? true : false; +$canOrder = $user->authorise('core.edit.state', 'com_newsfeeds.category'); +$saveOrder = $listOrder == 'a.ordering'; +if ($saveOrder) +{ + $saveOrderingUrl = 'index.php?option=com_newsfeeds&task=newsfeeds.saveOrderAjax&tmpl=component'; + JHtml::_('sortablelist.sortable', 'articleList', 'adminForm', strtolower($listDirn), $saveOrderingUrl); +} +$sortFields = $this->getSortFields(); +$assoc = isset($app->item_associations) ? $app->item_associations : 0; +?> + +
    +sidebar)) : ?> +
    + sidebar; ?> +
    +
    + +
    + +
    + +
    + + +
    +
    + + pagination->getLimitBox(); ?> +
    +
    + + +
    +
    + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + items as $i => $item) : + $ordering = ($listOrder == 'a.ordering'); + $canCreate = $user->authorise('core.create', 'com_newsfeeds.category.' . $item->catid); + $canEdit = $user->authorise('core.edit', 'com_newsfeeds.category.' . $item->catid); + $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id') || $item->checked_out == 0; + $canChange = $user->authorise('core.edit.state', 'com_newsfeeds.category.' . $item->catid) && $canCheckin; + ?> + + + + + + + + + + + + + + + + +
    + ', 'a.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING'); ?> + + + + + + + + + + + + + + + + + + +
    + pagination->getListFooter(); ?> +
    + + + + + + + + + id); ?> + + published, $i, 'newsfeeds.', $canChange, 'cb', $item->publish_up, $item->publish_down); ?> + +
    + checked_out) : ?> + editor, $item->checked_out_time, 'newsfeeds.', $canCheckin); ?> + + + + escape($item->name); ?> + + escape($item->name); ?> + + + escape($item->alias));?> + +
    + escape($item->category_title); ?> +
    +
    +
    + id, 'newsfeed.'); + JHtml::_('dropdown.divider'); + if ($item->published) : + JHtml::_('dropdown.unpublish', 'cb' . $i, 'newsfeeds.'); + else : + JHtml::_('dropdown.publish', 'cb' . $i, 'newsfeeds.'); + endif; + + JHtml::_('dropdown.divider'); + + if ($archived) : + JHtml::_('dropdown.unarchive', 'cb' . $i, 'newsfeeds.'); + else : + JHtml::_('dropdown.archive', 'cb' . $i, 'newsfeeds.'); + endif; + + if ($item->checked_out) : + JHtml::_('dropdown.checkin', 'cb' . $i, 'newsfeeds.'); + endif; + + if ($trashed) : + JHtml::_('dropdown.untrash', 'cb' . $i, 'newsfeeds.'); + else : + JHtml::_('dropdown.trash', 'cb' . $i, 'newsfeeds.'); + endif; + + // render dropdown list + echo JHtml::_('dropdown.render'); + ?> +
    + +
    + escape($item->access_level); ?> + + numarticles; ?> + + cache_time; ?> + + association) : ?> + id); ?> + + + language == '*'):?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + id; ?> +
    + + + loadTemplate('batch'); ?> + + + + + + +
    + diff --git a/administrator/components/com_newsfeeds/views/newsfeeds/tmpl/default_batch.php b/administrator/components/com_newsfeeds/views/newsfeeds/tmpl/default_batch.php new file mode 100644 index 0000000..fd32d17 --- /dev/null +++ b/administrator/components/com_newsfeeds/views/newsfeeds/tmpl/default_batch.php @@ -0,0 +1,52 @@ +state->get('filter.published'); +?> + diff --git a/administrator/components/com_newsfeeds/views/newsfeeds/tmpl/index.html b/administrator/components/com_newsfeeds/views/newsfeeds/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_newsfeeds/views/newsfeeds/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_newsfeeds/views/newsfeeds/tmpl/modal.php b/administrator/components/com_newsfeeds/views/newsfeeds/tmpl/modal.php new file mode 100644 index 0000000..78451e4 --- /dev/null +++ b/administrator/components/com_newsfeeds/views/newsfeeds/tmpl/modal.php @@ -0,0 +1,155 @@ +input; +$function = JFactory::getApplication()->input->getCmd('function', 'jSelectNewsfeed'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +?> +
    +
    +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +
    + + + + + state->get('filter.forcedLanguage')) : ?> + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + items as $i => $item) : ?> + language && JLanguageMultilang::isEnabled()) + { + $tag = strlen($item->language); + if ($tag == 5) + { + $lang = substr($item->language, 0, 2); + } + elseif ($tag == 6) + { + $lang = substr($item->language, 0, 3); + } + else { + $lang = ""; + } + } + elseif (!JLanguageMultilang::isEnabled()) + { + $lang = ""; + } + ?> + + + + + + + + + +
    + + + + + + + + + +
    + pagination->getListFooter(); ?> +
    + + escape($item->name); ?> + + escape($item->access_level); ?> + + escape($item->category_title); ?> + + language == '*'):?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + id; ?> +
    + +
    + + + + + +
    +
    diff --git a/administrator/components/com_newsfeeds/views/newsfeeds/view.html.php b/administrator/components/com_newsfeeds/views/newsfeeds/view.html.php new file mode 100644 index 0000000..4b4b801 --- /dev/null +++ b/administrator/components/com_newsfeeds/views/newsfeeds/view.html.php @@ -0,0 +1,160 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + NewsfeedsHelper::addSubmenu('newsfeeds'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + $state = $this->get('State'); + $canDo = NewsfeedsHelper::getActions($state->get('filter.category_id')); + $user = JFactory::getUser(); + // Get the toolbar object instance + $bar = JToolBar::getInstance('toolbar'); + JToolbarHelper::title(JText::_('COM_NEWSFEEDS_MANAGER_NEWSFEEDS'), 'newsfeeds.png'); + if (count($user->getAuthorisedCategories('com_newsfeeds', 'core.create')) > 0) + { + JToolbarHelper::addNew('newsfeed.add'); + } + if ($canDo->get('core.edit')) + { + JToolbarHelper::editList('newsfeed.edit'); + } + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::publish('newsfeeds.publish', 'JTOOLBAR_PUBLISH', true); + JToolbarHelper::unpublish('newsfeeds.unpublish', 'JTOOLBAR_UNPUBLISH', true); + JToolbarHelper::archiveList('newsfeeds.archive'); + } + if ($canDo->get('core.admin')) + { + JToolbarHelper::checkin('newsfeeds.checkin'); + } + if ($state->get('filter.published') == -2 && $canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'newsfeeds.delete', 'JTOOLBAR_EMPTY_TRASH'); + } elseif ($canDo->get('core.edit.state')) + { + JToolbarHelper::trash('newsfeeds.trash'); + } + // Add a batch button + if ($user->authorise('core.create', 'com_newsfeeds') && $user->authorise('core.edit', 'com_newsfeeds') && $user->authorise('core.edit.state', 'com_newsfeeds')) + { + JHtml::_('bootstrap.modal', 'collapseModal'); + $title = JText::_('JTOOLBAR_BATCH'); + + // Instantiate a new JLayoutFile instance and render the batch button + $layout = new JLayoutFile('joomla.toolbar.batch'); + + $dhtml = $layout->render(array('title' => $title)); + $bar->appendButton('Custom', $dhtml, 'batch'); + } + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_newsfeeds'); + } + JToolbarHelper::help('JHELP_COMPONENTS_NEWSFEEDS_FEEDS'); + + JHtmlSidebar::setAction('index.php?option=com_newsfeeds&view=newsfeeds'); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_published', + JHtml::_('select.options', JHtml::_('jgrid.publishedOptions'), 'value', 'text', $this->state->get('filter.published'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_CATEGORY'), + 'filter_category_id', + JHtml::_('select.options', JHtml::_('category.options', 'com_newsfeeds'), 'value', 'text', $this->state->get('filter.category_id')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_ACCESS'), + 'filter_access', + JHtml::_('select.options', JHtml::_('access.assetgroups'), 'value', 'text', $this->state->get('filter.access')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_LANGUAGE'), + 'filter_language', + JHtml::_('select.options', JHtml::_('contentlanguage.existing', true, true), 'value', 'text', $this->state->get('filter.language')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_TAG'), + 'filter_tag', + JHtml::_('select.options', JHtml::_('tag.options', true, true), 'value', 'text', $this->state->get('filter.tag')) + ); + } + + /** + * Returns an array of fields the table can be sorted by + * + * @return array Array containing the field name to sort by as the key and display text as value + * + * @since 3.0 + */ + protected function getSortFields() + { + return array( + 'a.ordering' => JText::_('JGRID_HEADING_ORDERING'), + 'a.published' => JText::_('JSTATUS'), + 'a.name' => JText::_('JGLOBAL_TITLE'), + 'category_title' => JText::_('JCATEGORY'), + 'a.access' => JText::_('JGRID_HEADING_ACCESS'), + 'numarticles' => JText::_('COM_NEWSFEEDS_NUM_ARTICLES_HEADING'), + 'a.cache_time' => JText::_('COM_NEWSFEEDS_CACHE_TIME_HEADING'), + 'a.language' => JText::_('JGRID_HEADING_LANGUAGE'), + 'a.id' => JText::_('JGRID_HEADING_ID') + ); + } +} diff --git a/administrator/components/com_plugins/access.xml b/administrator/components/com_plugins/access.xml new file mode 100644 index 0000000..c7e06d0 --- /dev/null +++ b/administrator/components/com_plugins/access.xml @@ -0,0 +1,9 @@ + + +
    + + + + +
    +
    diff --git a/administrator/components/com_plugins/config.xml b/administrator/components/com_plugins/config.xml new file mode 100644 index 0000000..1be01d3 --- /dev/null +++ b/administrator/components/com_plugins/config.xml @@ -0,0 +1,17 @@ + + +
    + + +
    +
    diff --git a/administrator/components/com_plugins/controller.php b/administrator/components/com_plugins/controller.php new file mode 100644 index 0000000..8c2fcbb --- /dev/null +++ b/administrator/components/com_plugins/controller.php @@ -0,0 +1,54 @@ +input->get('view', 'plugins')); + + $view = $this->input->get('view', 'plugins'); + $layout = $this->input->get('layout', 'default'); + $id = $this->input->getInt('extension_id'); + + // Check for edit form. + if ($view == 'plugin' && $layout == 'edit' && !$this->checkEditId('com_plugins.edit.plugin', $id)) + { + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_plugins&view=plugins', false)); + + return false; + } + + parent::display(); + } +} diff --git a/administrator/components/com_plugins/controllers/index.html b/administrator/components/com_plugins/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_plugins/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_plugins/controllers/plugin.php b/administrator/components/com_plugins/controllers/plugin.php new file mode 100644 index 0000000..4f71dfa --- /dev/null +++ b/administrator/components/com_plugins/controllers/plugin.php @@ -0,0 +1,21 @@ + true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } +} diff --git a/administrator/components/com_plugins/helpers/index.html b/administrator/components/com_plugins/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_plugins/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_plugins/helpers/plugins.php b/administrator/components/com_plugins/helpers/plugins.php new file mode 100644 index 0000000..03e8093 --- /dev/null +++ b/administrator/components/com_plugins/helpers/plugins.php @@ -0,0 +1,120 @@ +set($action->name, $user->authorise($action->name, $assetName)); + } + + return $result; + } + + /** + * Returns an array of standard published state filter options. + * + * @return string The HTML code for the select tag + */ + public static function publishedOptions() + { + // Build the active state filter options. + $options = array(); + $options[] = JHtml::_('select.option', '1', 'JENABLED'); + $options[] = JHtml::_('select.option', '0', 'JDISABLED'); + + return $options; + } + + /** + * Returns an array of standard published state filter options. + * + * @return string The HTML code for the select tag + */ + public static function folderOptions() + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('DISTINCT(folder) AS value, folder AS text') + ->from('#__extensions') + ->where($db->quoteName('type') . ' = ' . $db->quote('plugin')) + ->order('folder'); + + $db->setQuery($query); + + try + { + $options = $db->loadObjectList(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + } + + return $options; + } + + public function parseXMLTemplateFile($templateBaseDir, $templateDir) + { + $data = new JObject; + + // Check of the xml file exists + $filePath = JPath::clean($templateBaseDir . '/templates/' . $templateDir . '/templateDetails.xml'); + if (is_file($filePath)) + { + $xml = JInstaller::parseXMLInstallFile($filePath); + + if ($xml['type'] != 'template') + { + return false; + } + + foreach ($xml as $key => $value) + { + $data->set($key, $value); + } + } + + return $data; + } +} diff --git a/administrator/components/com_plugins/index.html b/administrator/components/com_plugins/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_plugins/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_plugins/models/fields/index.html b/administrator/components/com_plugins/models/fields/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_plugins/models/fields/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_plugins/models/fields/ordering.php b/administrator/components/com_plugins/models/fields/ordering.php new file mode 100644 index 0000000..2d21a99 --- /dev/null +++ b/administrator/components/com_plugins/models/fields/ordering.php @@ -0,0 +1,72 @@ +element['class'] ? ' class="'.(string) $this->element['class'].'"' : ''; + $attr .= ((string) $this->element['disabled'] == 'true') ? ' disabled="disabled"' : ''; + $attr .= $this->element['size'] ? ' size="'.(int) $this->element['size'].'"' : ''; + + // Initialize JavaScript field attributes. + $attr .= $this->element['onchange'] ? ' onchange="'.(string) $this->element['onchange'].'"' : ''; + + // Get some field values from the form. + $pluginId = (int) $this->form->getValue('extension_id'); + $folder = $this->form->getValue('folder'); + $db = JFactory::getDbo(); + + // Build the query for the ordering list. + $query = 'SELECT ordering AS value, name AS text, type AS type, folder AS folder, extension_id AS extension_id' . + ' FROM #__extensions' . + ' WHERE (type =' .$db->quote('plugin'). 'AND folder='. $db->quote($folder) . ')'. + ' ORDER BY ordering'; + + // Create a read-only list (no name) with a hidden input to store the value. + if ((string) $this->element['readonly'] == 'true') + { + $html[] = JHtml::_('list.ordering', '', $query, trim($attr), $this->value, $pluginId ? 0 : 1); + $html[] = ''; + } + // Create a regular list. + else { + $html[] = JHtml::_('list.ordering', $this->name, $query, trim($attr), $this->value, $pluginId ? 0 : 1); + } + + return implode($html); + } +} diff --git a/administrator/components/com_plugins/models/forms/index.html b/administrator/components/com_plugins/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_plugins/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_plugins/models/forms/plugin.xml b/administrator/components/com_plugins/models/forms/plugin.xml new file mode 100644 index 0000000..f31b6af --- /dev/null +++ b/administrator/components/com_plugins/models/forms/plugin.xml @@ -0,0 +1,65 @@ + +
    +
    + + + + + + + + + + + + + + + + + +
    +
    diff --git a/administrator/components/com_plugins/models/index.html b/administrator/components/com_plugins/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_plugins/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_plugins/models/plugin.php b/administrator/components/com_plugins/models/plugin.php new file mode 100644 index 0000000..722d7e2 --- /dev/null +++ b/administrator/components/com_plugins/models/plugin.php @@ -0,0 +1,334 @@ +getItem(); + $folder = $item->folder; + $element = $item->element; + } + else + { + $folder = JArrayHelper::getValue($data, 'folder', '', 'cmd'); + $element = JArrayHelper::getValue($data, 'element', '', 'cmd'); + } + + // These variables are used to add data from the plugin XML files. + $this->setState('item.folder', $folder); + $this->setState('item.element', $element); + + // Get the form. + $form = $this->loadForm('com_plugins.plugin', 'plugin', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + // Modify the form based on access controls. + if (!$this->canEditState((object) $data)) + { + // Disable fields for display. + $form->setFieldAttribute('ordering', 'disabled', 'true'); + $form->setFieldAttribute('enabled', 'disabled', 'true'); + + // Disable fields while saving. + // The controller has already verified this is a record you can edit. + $form->setFieldAttribute('ordering', 'filter', 'unset'); + $form->setFieldAttribute('enabled', 'filter', 'unset'); + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_plugins.edit.plugin.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + } + + $this->preprocessData('com_plugins.plugin', $data); + + return $data; + } + + /** + * Method to get a single record. + * + * @param integer The id of the primary key. + * + * @return mixed Object on success, false on failure. + */ + public function getItem($pk = null) + { + $pk = (!empty($pk)) ? $pk : (int) $this->getState('plugin.id'); + + if (!isset($this->_cache[$pk])) + { + $false = false; + + // Get a row instance. + $table = $this->getTable(); + + // Attempt to load the row. + $return = $table->load($pk); + + // Check for a table object error. + if ($return === false && $table->getError()) + { + $this->setError($table->getError()); + return $false; + } + + // Convert to the JObject before adding other data. + $properties = $table->getProperties(1); + $this->_cache[$pk] = JArrayHelper::toObject($properties, 'JObject'); + + // Convert the params field to an array. + $registry = new JRegistry; + $registry->loadString($table->params); + $this->_cache[$pk]->params = $registry->toArray(); + + // Get the plugin XML. + $path = JPath::clean(JPATH_PLUGINS.'/'.$table->folder.'/'.$table->element.'/'.$table->element.'.xml'); + + if (file_exists($path)) + { + $this->_cache[$pk]->xml = simplexml_load_file($path); + } else { + $this->_cache[$pk]->xml = null; + } + } + + return $this->_cache[$pk]; + } + + /** + * Returns a reference to the a Table object, always creating it. + * + * @param type The table type to instantiate + * @param string A prefix for the table class name. Optional. + * @param array Configuration array for model. Optional. + * @return JTable A database object + */ + public function getTable($type = 'Extension', $prefix = 'JTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @return void + * @since 1.6 + */ + protected function populateState() + { + // Execute the parent method. + parent::populateState(); + + $app = JFactory::getApplication('administrator'); + + // Load the User state. + $pk = $app->input->getInt('extension_id'); + $this->setState('plugin.id', $pk); + } + + /** + * @param object A form object. + * @param mixed The data expected for the form. + * @return mixed True if successful. + * @throws Exception if there is an error in the form event. + * @since 1.6 + */ + protected function preprocessForm(JForm $form, $data, $group = 'content') + { + jimport('joomla.filesystem.path'); + + $folder = $this->getState('item.folder'); + $element = $this->getState('item.element'); + $lang = JFactory::getLanguage(); + + // Load the core and/or local language sys file(s) for the ordering field. + $db = JFactory::getDbo(); + $query = 'SELECT element' . + ' FROM #__extensions' . + ' WHERE (type =' .$db->quote('plugin'). 'AND folder='. $db->quote($folder) . ')'; + $db->setQuery($query); + $elements = $db->loadColumn(); + + foreach ($elements as $elementa) + { + $lang->load('plg_'.$folder.'_'.$elementa.'.sys', JPATH_ADMINISTRATOR, null, false, false) + || $lang->load('plg_'.$folder.'_'.$elementa.'.sys', JPATH_PLUGINS.'/'.$folder.'/'.$elementa, null, false, false) + || $lang->load('plg_'.$folder.'_'.$elementa.'.sys', JPATH_ADMINISTRATOR, $lang->getDefault(), false, false) + || $lang->load('plg_'.$folder.'_'.$elementa.'.sys', JPATH_PLUGINS.'/'.$folder.'/'.$elementa, $lang->getDefault(), false, false); + } + + if (empty($folder) || empty($element)) + { + $app = JFactory::getApplication(); + $app->redirect(JRoute::_('index.php?option=com_plugins&view=plugins', false)); + } + + $formFile = JPath::clean(JPATH_PLUGINS . '/' . $folder . '/' . $element . '/' . $element . '.xml'); + if (!file_exists($formFile)) + { + throw new Exception(JText::sprintf('COM_PLUGINS_ERROR_FILE_NOT_FOUND', $element . '.xml')); + } + + // Load the core and/or local language file(s). + $lang->load('plg_'.$folder.'_'.$element, JPATH_ADMINISTRATOR, null, false, false) + || $lang->load('plg_'.$folder.'_'.$element, JPATH_PLUGINS.'/'.$folder.'/'.$element, null, false, false) + || $lang->load('plg_'.$folder.'_'.$element, JPATH_ADMINISTRATOR, $lang->getDefault(), false, false) + || $lang->load('plg_'.$folder.'_'.$element, JPATH_PLUGINS.'/'.$folder.'/'.$element, $lang->getDefault(), false, false); + + if (file_exists($formFile)) + { + // Get the plugin form. + if (!$form->loadFile($formFile, false, '//config')) + { + throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); + } + } + + // Attempt to load the xml file. + if (!$xml = simplexml_load_file($formFile)) + { + throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); + } + + // Get the help data from the XML file if present. + $help = $xml->xpath('/extension/help'); + if (!empty($help)) + { + $helpKey = trim((string) $help[0]['key']); + $helpURL = trim((string) $help[0]['url']); + + $this->helpKey = $helpKey ? $helpKey : $this->helpKey; + $this->helpURL = $helpURL ? $helpURL : $this->helpURL; + } + + // Trigger the default form events. + parent::preprocessForm($form, $data, $group); + } + + /** + * A protected method to get a set of ordering conditions. + * + * @param object A record object. + * @return array An array of conditions to add to add to ordering queries. + * @since 1.6 + */ + protected function getReorderConditions($table) + { + $condition = array(); + $condition[] = 'type = '. $this->_db->quote($table->type); + $condition[] = 'folder = '. $this->_db->quote($table->folder); + return $condition; + } + + /** + * Override method to save the form data. + * + * @param array The form data. + * @return boolean True on success. + * @since 1.6 + */ + public function save($data) + { + // Load the extension plugin group. + JPluginHelper::importPlugin('extension'); + + // Setup type + $data['type'] = 'plugin'; + + return parent::save($data); + } + + /** + * Get the necessary data to load an item help screen. + * + * @return object An object with key, url, and local properties for loading the item help screen. + * @since 1.6 + */ + public function getHelp() + { + return (object) array('key' => $this->helpKey, 'url' => $this->helpURL); + } + + /** + * Custom clean cache method, plugins are cached in 2 places for different clients + * + * @since 1.6 + */ + protected function cleanCache($group = null, $client_id = 0) + { + parent::cleanCache('com_plugins'); + } +} diff --git a/administrator/components/com_plugins/models/plugins.php b/administrator/components/com_plugins/models/plugins.php new file mode 100644 index 0000000..8accf70 --- /dev/null +++ b/administrator/components/com_plugins/models/plugins.php @@ -0,0 +1,260 @@ +getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $accessId = $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access', null, 'int'); + $this->setState('filter.access', $accessId); + + $state = $this->getUserStateFromRequest($this->context . '.filter.enabled', 'filter_enabled', '', 'string'); + $this->setState('filter.enabled', $state); + + $folder = $this->getUserStateFromRequest($this->context . '.filter.folder', 'filter_folder', null, 'cmd'); + $this->setState('filter.folder', $folder); + + $language = $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', ''); + $this->setState('filter.language', $language); + + // Load the parameters. + $params = JComponentHelper::getParams('com_plugins'); + $this->setState('params', $params); + + // List state information. + parent::populateState('folder', 'asc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string A prefix for the store id. + * + * @return string A store id. + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.access'); + $id .= ':' . $this->getState('filter.state'); + $id .= ':' . $this->getState('filter.folder'); + $id .= ':' . $this->getState('filter.language'); + + return parent::getStoreId($id); + } + + /** + * Returns an object list + * + * @param string The query + * @param int Offset + * @param int The number of records + * @return array + */ + protected function _getList($query, $limitstart = 0, $limit = 0) + { + $search = $this->getState('filter.search'); + $ordering = $this->getState('list.ordering', 'ordering'); + if ($ordering == 'name' || (!empty($search) && stripos($search, 'id:') !== 0)) + { + $this->_db->setQuery($query); + $result = $this->_db->loadObjectList(); + $this->translate($result); + if (!empty($search)) + { + foreach ($result as $i => $item) + { + if (!preg_match("/$search/i", $item->name)) + { + unset($result[$i]); + } + } + } + + $direction = ($this->getState('list.direction') == 'desc') ? -1 : 1; + JArrayHelper::sortObjects($result, $ordering, $direction, true, true); + + $total = count($result); + $this->cache[$this->getStoreId('getTotal')] = $total; + if ($total < $limitstart) + { + $limitstart = 0; + $this->setState('list.start', 0); + } + return array_slice($result, $limitstart, $limit ? $limit : null); + } + else + { + if ($ordering == 'ordering') + { + $query->order('a.folder ASC'); + $ordering = 'a.ordering'; + } + $query->order($this->_db->quoteName($ordering) . ' ' . $this->getState('list.direction')); + + if ($ordering == 'folder') + { + $query->order('a.ordering ASC'); + } + $result = parent::_getList($query, $limitstart, $limit); + $this->translate($result); + return $result; + } + } + + /** + * Translate a list of objects + * + * @param array The array of objects + * @return array The array of translated objects + */ + protected function translate(&$items) + { + $lang = JFactory::getLanguage(); + + foreach ($items as &$item) + { + $source = JPATH_PLUGINS . '/' . $item->folder . '/' . $item->element; + $extension = 'plg_' . $item->folder . '_' . $item->element; + $lang->load($extension . '.sys', JPATH_ADMINISTRATOR, null, false, false) + || $lang->load($extension . '.sys', $source, null, false, false) + || $lang->load($extension . '.sys', JPATH_ADMINISTRATOR, $lang->getDefault(), false, false) + || $lang->load($extension . '.sys', $source, $lang->getDefault(), false, false); + $item->name = JText::_($item->name); + } + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.extension_id , a.name, a.element, a.folder, a.checked_out, a.checked_out_time,' . + ' a.enabled, a.access, a.ordering' + ) + ) + ->from($db->quoteName('#__extensions') . ' AS a') + ->where($db->quoteName('type') . ' = ' . $db->quote('plugin')); + + // Join over the users for the checked out user. + $query->select('uc.name AS editor') + ->join('LEFT', '#__users AS uc ON uc.id=a.checked_out'); + + // Join over the asset groups. + $query->select('ag.title AS access_level') + ->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access'); + + // Filter by access level. + if ($access = $this->getState('filter.access')) + { + $query->where('a.access = ' . (int) $access); + } + + // Filter by published state + $published = $this->getState('filter.enabled'); + if (is_numeric($published)) + { + $query->where('a.enabled = ' . (int) $published); + } + elseif ($published === '') + { + $query->where('(a.enabled IN (0, 1))'); + } + + // Filter by state + $query->where('a.state >= 0'); + + // Filter by folder. + if ($folder = $this->getState('filter.folder')) + { + $query->where('a.folder = ' . $db->quote($folder)); + } + + // Filter by search in name or id + $search = $this->getState('filter.search'); + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.extension_id = ' . (int) substr($search, 3)); + } + } + + return $query; + } +} diff --git a/administrator/components/com_plugins/plugins.php b/administrator/components/com_plugins/plugins.php new file mode 100644 index 0000000..07d666e --- /dev/null +++ b/administrator/components/com_plugins/plugins.php @@ -0,0 +1,19 @@ +authorise('core.manage', 'com_plugins')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$controller = JControllerLegacy::getInstance('Plugins'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_plugins/plugins.xml b/administrator/components/com_plugins/plugins.xml new file mode 100644 index 0000000..b9bba03 --- /dev/null +++ b/administrator/components/com_plugins/plugins.xml @@ -0,0 +1,28 @@ + + + com_plugins + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_PLUGINS_XML_DESCRIPTION + + + config.xml + controller.php + index.html + plugins.php + controllers + helpers + models + views + + + language/en-GB.com_plugins.ini + language/en-GB.com_plugins.sys.ini + + + diff --git a/administrator/components/com_plugins/views/index.html b/administrator/components/com_plugins/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_plugins/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_plugins/views/plugin/index.html b/administrator/components/com_plugins/views/plugin/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_plugins/views/plugin/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_plugins/views/plugin/tmpl/edit.php b/administrator/components/com_plugins/views/plugin/tmpl/edit.php new file mode 100644 index 0000000..0795e11 --- /dev/null +++ b/administrator/components/com_plugins/views/plugin/tmpl/edit.php @@ -0,0 +1,118 @@ +fieldsets = $this->form->getFieldsets('params'); +?> + + +
    +
    + 'details')); ?> + + +
    +
    + form->getLabel('name'); ?> +
    +
    + form->getInput('name'); ?> + item->name);?> +
    +
    +
    +
    + form->getLabel('enabled'); ?> +
    +
    + form->getInput('enabled'); ?> +
    +
    +
    +
    + form->getLabel('access'); ?> +
    +
    + form->getInput('access'); ?> +
    +
    +
    +
    + form->getLabel('ordering'); ?> +
    +
    + form->getInput('ordering'); ?> +
    +
    +
    +
    + form->getLabel('folder'); ?> +
    +
    + form->getInput('folder'); ?> +
    +
    +
    +
    + form->getLabel('element'); ?> +
    +
    + form->getInput('element'); ?> +
    +
    + item->extension_id) : ?> +
    +
    + form->getLabel('extension_id'); ?> +
    +
    + form->getInput('extension_id'); ?> +
    +
    + + + item->xml) : ?> + item->xml->description)) : ?> +
    + +
    + +
    +
    + + +
    + +
    + + + + loadTemplate('options'); ?> + + +
    + + + +
    diff --git a/administrator/components/com_plugins/views/plugin/tmpl/edit_options.php b/administrator/components/com_plugins/views/plugin/tmpl/edit_options.php new file mode 100644 index 0000000..9e1457b --- /dev/null +++ b/administrator/components/com_plugins/views/plugin/tmpl/edit_options.php @@ -0,0 +1,38 @@ +fieldsets as $name => $fieldset) : + $label = !empty($fieldset->label) ? JText::_($fieldset->label, true) : JText::_('COM_PLUGINS_'.$fieldset->name.'_FIELDSET_LABEL', true); + $optionsname = 'options-' . $fieldset->name; + echo JHtml::_('bootstrap.addTab', 'myTab', $optionsname, $label); + if (isset($fieldset->description) && trim($fieldset->description)) : + echo '

    '.$this->escape(JText::_($fieldset->description)).'

    '; + endif; + ?> + + form->getFieldset($name) as $field) : ?> + hidden) : ?> +
    +
    + label; ?> +
    +
    + input; ?> +
    +
    + input; ?> + + + + + + + diff --git a/administrator/components/com_plugins/views/plugin/tmpl/index.html b/administrator/components/com_plugins/views/plugin/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_plugins/views/plugin/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_plugins/views/plugin/view.html.php b/administrator/components/com_plugins/views/plugin/view.html.php new file mode 100644 index 0000000..d9aaf44 --- /dev/null +++ b/administrator/components/com_plugins/views/plugin/view.html.php @@ -0,0 +1,85 @@ +state = $this->get('State'); + $this->item = $this->get('Item'); + $this->form = $this->get('Form'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + JFactory::getApplication()->input->set('hidemainmenu', true); + + $canDo = PluginsHelper::getActions(); + + JToolbarHelper::title(JText::sprintf('COM_PLUGINS_MANAGER_PLUGIN', JText::_($this->item->name)), 'plugin'); + + // If not checked out, can save the item. + if ($canDo->get('core.edit')) + { + JToolbarHelper::apply('plugin.apply'); + JToolbarHelper::save('plugin.save'); + } + JToolbarHelper::cancel('plugin.cancel', 'JTOOLBAR_CLOSE'); + JToolbarHelper::divider(); + // Get the help information for the plugin item. + + $lang = JFactory::getLanguage(); + + $help = $this->get('Help'); + if ($lang->hasKey($help->url)) + { + $debug = $lang->setDebug(false); + $url = JText::_($help->url); + $lang->setDebug($debug); + } + else + { + $url = null; + } + JToolbarHelper::help($help->key, false, $url); + } +} diff --git a/administrator/components/com_plugins/views/plugins/index.html b/administrator/components/com_plugins/views/plugins/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_plugins/views/plugins/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_plugins/views/plugins/tmpl/default.php b/administrator/components/com_plugins/views/plugins/tmpl/default.php new file mode 100644 index 0000000..6710fc2 --- /dev/null +++ b/administrator/components/com_plugins/views/plugins/tmpl/default.php @@ -0,0 +1,191 @@ +escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$canOrder = $user->authorise('core.edit.state', 'com_plugins'); +$saveOrder = $listOrder == 'ordering'; +if ($saveOrder) +{ + $saveOrderingUrl = 'index.php?option=com_plugins&task=plugins.saveOrderAjax&tmpl=component'; + JHtml::_('sortablelist.sortable', 'articleList', 'adminForm', strtolower($listDirn), $saveOrderingUrl); +} +$sortFields = $this->getSortFields(); +?> + +
    +sidebar)) : ?> + +
    + +
    + +
    + +
    + + +
    +
    + + pagination->getLimitBox(); ?> +
    +
    + + +
    +
    + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + items as $i => $item) : + $ordering = ($listOrder == 'ordering'); + $canEdit = $user->authorise('core.edit', 'com_plugins'); + $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id') || $item->checked_out == 0; + $canChange = $user->authorise('core.edit.state', 'com_plugins') && $canCheckin; + ?> + + + + + + + + + + + + +
    + ', 'ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING'); ?> + + + + + + + + + + + + + + +
    + pagination->getListFooter(); ?> +
    + + + + + + + + + extension_id); ?> + + enabled, $i, 'plugins.', $canChange); ?> + + checked_out) : ?> + editor, $item->checked_out_time, 'plugins.', $canCheckin); ?> + + + + name; ?> + + name; ?> + + + escape($item->folder);?> + + escape($item->element);?> + + escape($item->access_level); ?> + + extension_id;?> +
    + + + + + + +
    + diff --git a/administrator/components/com_plugins/views/plugins/tmpl/index.html b/administrator/components/com_plugins/views/plugins/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_plugins/views/plugins/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_plugins/views/plugins/view.html.php b/administrator/components/com_plugins/views/plugins/view.html.php new file mode 100644 index 0000000..7ca8c03 --- /dev/null +++ b/administrator/components/com_plugins/views/plugins/view.html.php @@ -0,0 +1,129 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + // Check if there are no matching items + if (!count($this->items)) + { + JFactory::getApplication()->enqueueMessage( + JText::_('COM_PLUGINS_MSG_MANAGE_NO_PLUGINS'), + 'warning' + ); + } + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + $canDo = PluginsHelper::getActions(); + + JToolbarHelper::title(JText::_('COM_PLUGINS_MANAGER_PLUGINS'), 'plugin'); + + if ($canDo->get('core.edit')) + { + JToolbarHelper::editList('plugin.edit'); + } + + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::publish('plugins.publish', 'JTOOLBAR_ENABLE', true); + JToolbarHelper::unpublish('plugins.unpublish', 'JTOOLBAR_DISABLE', true); + JToolbarHelper::checkin('plugins.checkin'); + } + + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_plugins'); + } + + JToolbarHelper::help('JHELP_EXTENSIONS_PLUGIN_MANAGER'); + + JHtmlSidebar::setAction('index.php?option=com_plugins&view=plugins'); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_enabled', + JHtml::_('select.options', PluginsHelper::publishedOptions(), 'value', 'text', $this->state->get('filter.enabled'), true) + ); + + JHtmlSidebar::addFilter( + JText::_('COM_PLUGINS_OPTION_FOLDER'), + 'filter_folder', + JHtml::_('select.options', PluginsHelper::folderOptions(), 'value', 'text', $this->state->get('filter.folder')) + ); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_ACCESS'), + 'filter_access', + JHtml::_('select.options', JHtml::_('access.assetgroups'), 'value', 'text', $this->state->get('filter.access')) + ); + + $this->sidebar = JHtmlSidebar::render(); + + } + + /** + * Returns an array of fields the table can be sorted by + * + * @return array Array containing the field name to sort by as the key and display text as value + * + * @since 3.0 + */ + protected function getSortFields() + { + return array( + 'ordering' => JText::_('JGRID_HEADING_ORDERING'), + 'a.state' => JText::_('JSTATUS'), + 'name' => JText::_('JGLOBAL_TITLE'), + 'folder' => JText::_('COM_PLUGINS_FOLDER_HEADING'), + 'element' => JText::_('COM_PLUGINS_ELEMENT_HEADING'), + 'access' => JText::_('JGRID_HEADING_ACCESS'), + 'extension_id' => JText::_('JGRID_HEADING_ID') + ); + } +} diff --git a/administrator/components/com_redirect/access.xml b/administrator/components/com_redirect/access.xml new file mode 100644 index 0000000..f571c60 --- /dev/null +++ b/administrator/components/com_redirect/access.xml @@ -0,0 +1,11 @@ + + +
    + + + + + + +
    +
    diff --git a/administrator/components/com_redirect/config.xml b/administrator/components/com_redirect/config.xml new file mode 100644 index 0000000..fa9f732 --- /dev/null +++ b/administrator/components/com_redirect/config.xml @@ -0,0 +1,17 @@ + + +
    + + +
    +
    diff --git a/administrator/components/com_redirect/controller.php b/administrator/components/com_redirect/controller.php new file mode 100644 index 0000000..c99282c --- /dev/null +++ b/administrator/components/com_redirect/controller.php @@ -0,0 +1,60 @@ +input->get('view', 'links')); + + $view = $this->input->get('view', 'links'); + $layout = $this->input->get('layout', 'default'); + $id = $this->input->getInt('id'); + + // Check for edit form. + if ($view == 'link' && $layout == 'edit' && !$this->checkEditId('com_redirect.edit.link', $id)) + { + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_redirect&view=links', false)); + + return false; + } + + parent::display(); + } +} diff --git a/administrator/components/com_redirect/controllers/index.html b/administrator/components/com_redirect/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_redirect/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_redirect/controllers/link.php b/administrator/components/com_redirect/controllers/link.php new file mode 100644 index 0000000..7face9e --- /dev/null +++ b/administrator/components/com_redirect/controllers/link.php @@ -0,0 +1,22 @@ +input->get('cid', array(), 'array'); + $newUrl = $this->input->getString('new_url'); + $comment = $this->input->getString('comment'); + + if (empty($ids)) + { + JError::raiseWarning(500, JText::_('COM_REDIRECT_NO_ITEM_SELECTED')); + } + else + { + // Get the model. + $model = $this->getModel(); + + JArrayHelper::toInteger($ids); + + // Remove the items. + if (!$model->activate($ids, $newUrl, $comment)) + { + JError::raiseWarning(500, $model->getError()); + } + else { + $this->setMessage(JText::plural('COM_REDIRECT_N_LINKS_UPDATED', count($ids))); + } + } + + $this->setRedirect('index.php?option=com_redirect&view=links'); + } + + /** + * Proxy for getModel. + * @since 1.6 + */ + public function getModel($name = 'Link', $prefix = 'RedirectModel', $config = array('ignore_request' => true)) + { + $model = parent::getModel($name, $prefix, $config); + + return $model; + } +} diff --git a/administrator/components/com_redirect/helpers/html/index.html b/administrator/components/com_redirect/helpers/html/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_redirect/helpers/html/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_redirect/helpers/html/redirect.php b/administrator/components/com_redirect/helpers/html/redirect.php new file mode 100644 index 0000000..fab9260 --- /dev/null +++ b/administrator/components/com_redirect/helpers/html/redirect.php @@ -0,0 +1,47 @@ + array('tick.png', 'links.unpublish', 'JENABLED', 'COM_REDIRECT_DISABLE_LINK'), + 0 => array('publish_x.png', 'links.publish', 'JDISABLED', 'COM_REDIRECT_ENABLE_LINK'), + 2 => array('disabled.png', 'links.unpublish', 'JARCHIVED', 'JUNARCHIVE'), + -2 => array('trash.png', 'links.publish', 'JTRASHED', 'COM_REDIRECT_ENABLE_LINK'), + ); + $state = JArrayHelper::getValue($states, (int) $value, $states[0]); + $html = JHtml::_('image', 'admin/'.$state[0], JText::_($state[2]), null, true); + if ($canChange) + { + $html = '' + . $html.''; + } + + return $html; + } +} diff --git a/administrator/components/com_redirect/helpers/index.html b/administrator/components/com_redirect/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_redirect/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_redirect/helpers/redirect.php b/administrator/components/com_redirect/helpers/redirect.php new file mode 100644 index 0000000..12729dc --- /dev/null +++ b/administrator/components/com_redirect/helpers/redirect.php @@ -0,0 +1,98 @@ +set($action->name, $user->authorise($action->name, $assetName)); + } + + return $result; + } + + /** + * Returns an array of standard published state filter options. + * + * @return string The HTML code for the select tag + */ + public static function publishedOptions() + { + // Build the active state filter options. + $options = array(); + $options[] = JHtml::_('select.option', '*', 'JALL'); + $options[] = JHtml::_('select.option', '1', 'JENABLED'); + $options[] = JHtml::_('select.option', '0', 'JDISABLED'); + $options[] = JHtml::_('select.option', '2', 'JARCHIVED'); + $options[] = JHtml::_('select.option', '-2', 'JTRASHED'); + + return $options; + } + + /** + * Determines if the plugin for Redirect to work is enabled. + * + * @return boolean + */ + public static function isEnabled() + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select($db->quoteName('enabled')) + ->from('#__extensions') + ->where($db->quoteName('folder') . ' = ' . $db->quote('system')) + ->where($db->quoteName('element') . ' = ' . $db->quote('redirect')); + $db->setQuery($query); + + try + { + $result = (boolean) $db->loadResult(); + } + catch (RuntimeException $e) + { + JError::raiseWarning(500, $e->getMessage()); + } + + return $result; + } +} diff --git a/administrator/components/com_redirect/index.html b/administrator/components/com_redirect/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_redirect/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_redirect/models/forms/index.html b/administrator/components/com_redirect/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_redirect/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_redirect/models/forms/link.xml b/administrator/components/com_redirect/models/forms/link.xml new file mode 100644 index 0000000..54033f7 --- /dev/null +++ b/administrator/components/com_redirect/models/forms/link.xml @@ -0,0 +1,100 @@ + +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    +
    diff --git a/administrator/components/com_redirect/models/index.html b/administrator/components/com_redirect/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_redirect/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_redirect/models/link.php b/administrator/components/com_redirect/models/link.php new file mode 100644 index 0000000..e025a34 --- /dev/null +++ b/administrator/components/com_redirect/models/link.php @@ -0,0 +1,180 @@ +published != -2) + { + return false; + } + $user = JFactory::getUser(); + return $user->authorise('core.admin', 'com_redirect'); + } + + /** + * Method to test whether a record can have its state edited. + * + * @param object $record A record object. + * + * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. + * @since 1.6 + */ + protected function canEditState($record) + { + $user = JFactory::getUser(); + + // Check the component since there are no categories or other assets. + return $user->authorise('core.admin', 'com_redirect'); + } + + /** + * Returns a reference to the a Table object, always creating it. + * + * @param type The table type to instantiate + * @param string A prefix for the table class name. Optional. + * @param array Configuration array for model. Optional. + * @return JTable A database object + * @since 1.6 + */ + public function getTable($type = 'Link', $prefix = 'RedirectTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Method to get the record form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * @return JForm A JForm object on success, false on failure + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + // Get the form. + $form = $this->loadForm('com_redirect.link', 'link', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + // Modify the form based on access controls. + if ($this->canEditState((object) $data) != true) + { + // Disable fields for display. + $form->setFieldAttribute('published', 'disabled', 'true'); + + // Disable fields while saving. + // The controller has already verified this is a record you can edit. + $form->setFieldAttribute('published', 'filter', 'unset'); + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_redirect.edit.link.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + } + + $this->preprocessData('com_redirect.link', $data); + + return $data; + } + + /** + * Method to activate links. + * + * @param array An array of link ids. + * @param string The new URL to set for the redirect. + * @param string A comment for the redirect links. + * @return boolean Returns true on success, false on failure. + * @since 1.6 + */ + public function activate(&$pks, $url, $comment = null) + { + $user = JFactory::getUser(); + $db = $this->getDbo(); + + // Sanitize the ids. + $pks = (array) $pks; + JArrayHelper::toInteger($pks); + + // Populate default comment if necessary. + $comment = (!empty($comment)) ? $comment : JText::sprintf('COM_REDIRECT_REDIRECTED_ON', JHtml::_('date', time())); + + // Access checks. + if (!$user->authorise('core.admin', 'com_redirect')) + { + $pks = array(); + $this->setError(JText::_('JLIB_APPLICATION_ERROR_EDIT_NOT_PERMITTED')); + return false; + } + + if (!empty($pks)) + { + // Update the link rows. + $query = $db->getQuery(true) + ->update($db->quoteName('#__redirect_links')) + ->set($db->quoteName('new_url') . ' = ' . $db->quote($url)) + ->set($db->quoteName('published') . ' = ' . $db->quote(1)) + ->set($db->quoteName('comment') . ' = ' . $db->quote($comment)) + ->where($db->quoteName('id') . ' IN (' . implode(',', $pks) . ')'); + $db->setQuery($query); + + try + { + $db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + } + return true; + } +} diff --git a/administrator/components/com_redirect/models/links.php b/administrator/components/com_redirect/models/links.php new file mode 100644 index 0000000..402b0f3 --- /dev/null +++ b/administrator/components/com_redirect/models/links.php @@ -0,0 +1,154 @@ +getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $state = $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string'); + $this->setState('filter.state', $state); + + // Load the parameters. + $params = JComponentHelper::getParams('com_redirect'); + $this->setState('params', $params); + + // List state information. + parent::populateState('a.old_url', 'asc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string A prefix for the store id. + * + * @return string A store id. + * @since 1.6 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.state'); + + return parent::getStoreId($id); + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery + * @since 1.6 + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.*' + ) + ); + $query->from($db->quoteName('#__redirect_links') . ' AS a'); + + // Filter by published state + $state = $this->getState('filter.state'); + if (is_numeric($state)) + { + $query->where('a.published = ' . (int) $state); + } + elseif ($state === '') + { + $query->where('(a.published IN (0,1,2))'); + } + + // Filter the items over the search string if set. + $search = $this->getState('filter.search'); + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + else + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where( + '(' . $db->quoteName('old_url') . ' LIKE ' . $search . + ' OR ' . $db->quoteName('new_url') . ' LIKE ' . $search . + ' OR ' . $db->quoteName('comment') . ' LIKE ' . $search . + ' OR ' . $db->quoteName('referer') . ' LIKE ' . $search . ')' + ); + } + } + + // Add the list ordering clause. + $query->order($db->escape($this->getState('list.ordering', 'a.old_url')) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))); + + //echo nl2br(str_replace('#__','jos_',$query)); + return $query; + } +} diff --git a/administrator/components/com_redirect/redirect.php b/administrator/components/com_redirect/redirect.php new file mode 100644 index 0000000..6db20c4 --- /dev/null +++ b/administrator/components/com_redirect/redirect.php @@ -0,0 +1,19 @@ +authorise('core.manage', 'com_redirect')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$controller = JControllerLegacy::getInstance('Redirect'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_redirect/redirect.xml b/administrator/components/com_redirect/redirect.xml new file mode 100644 index 0000000..969d628 --- /dev/null +++ b/administrator/components/com_redirect/redirect.xml @@ -0,0 +1,31 @@ + + + com_redirect + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_REDIRECT_XML_DESCRIPTION + + Redirect + + + config.xml + controller.php + index.html + redirect.php + controllers + helpers + models + tables + views + + + language/en-GB.com_redirect.ini + language/en-GB.com_redirect.sys.ini + + + diff --git a/administrator/components/com_redirect/tables/index.html b/administrator/components/com_redirect/tables/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_redirect/tables/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_redirect/tables/link.php b/administrator/components/com_redirect/tables/link.php new file mode 100644 index 0000000..ef405d0 --- /dev/null +++ b/administrator/components/com_redirect/tables/link.php @@ -0,0 +1,112 @@ +old_url = trim($this->old_url); + $this->new_url = trim($this->new_url); + + // Check for valid name. + if (empty($this->old_url)) + { + $this->setError(JText::_('COM_REDIRECT_ERROR_SOURCE_URL_REQUIRED')); + return false; + } + + // Check for valid name. + if (empty($this->new_url)) + { + $this->setError(JText::_('COM_REDIRECT_ERROR_DESTINATION_URL_REQUIRED')); + return false; + } + + // Check for duplicates + if ($this->old_url == $this->new_url) + { + $this->setError(JText::_('COM_REDIRECT_ERROR_DUPLICATE_URLS')); + return false; + } + + $db = $this->getDbo(); + + // Check for existing name + $query = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from('#__redirect_links') + ->where($db->quoteName('old_url') . ' = ' . $db->quote($this->old_url)); + $db->setQuery($query); + + $xid = (int) $db->loadResult(); + + if ($xid && $xid != (int) $this->id) + { + $this->setError(JText::_('COM_REDIRECT_ERROR_DUPLICATE_OLD_URL')); + return false; + } + + return true; + } + + /** + * Overriden store method to set dates. + * + * @param boolean True to update fields even if they are null. + * + * @return boolean True on success. + * @see JTable::store + * @since 1.6 + */ + public function store($updateNulls = false) + { + $date = JFactory::getDate()->toSql(); + + if ($this->id) + { + // Existing item + $this->modified_date = $date; + } + else + { + // New record. + $this->created_date = $date; + } + + return parent::store($updateNulls); + } +} diff --git a/administrator/components/com_redirect/views/index.html b/administrator/components/com_redirect/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_redirect/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_redirect/views/link/index.html b/administrator/components/com_redirect/views/link/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_redirect/views/link/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_redirect/views/link/tmpl/edit.php b/administrator/components/com_redirect/views/link/tmpl/edit.php new file mode 100644 index 0000000..63caf1c --- /dev/null +++ b/administrator/components/com_redirect/views/link/tmpl/edit.php @@ -0,0 +1,69 @@ + + + + diff --git a/administrator/components/com_redirect/views/link/tmpl/index.html b/administrator/components/com_redirect/views/link/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_redirect/views/link/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_redirect/views/link/view.html.php b/administrator/components/com_redirect/views/link/view.html.php new file mode 100644 index 0000000..87fb55f --- /dev/null +++ b/administrator/components/com_redirect/views/link/view.html.php @@ -0,0 +1,89 @@ +form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + JFactory::getApplication()->input->set('hidemainmenu', true); + + $canDo = RedirectHelper::getActions(); + + JToolbarHelper::title(JText::_('COM_REDIRECT_MANAGER_LINK'), 'redirect'); + + // If not checked out, can save the item. + if ($canDo->get('core.edit')) + { + JToolbarHelper::apply('link.apply'); + JToolbarHelper::save('link.save'); + } + + // This component does not support Save as Copy due to uniqueness checks. + // While it can be done, it causes too much confusion if the user does + // not change the Old URL. + + if ($canDo->get('core.edit') && $canDo->get('core.create')) + { + JToolbarHelper::save2new('link.save2new'); + } + + if (empty($this->item->id)) + { + JToolbarHelper::cancel('link.cancel'); + } + else + { + JToolbarHelper::cancel('link.cancel', 'JTOOLBAR_CLOSE'); + } + + JToolbarHelper::help('JHELP_COMPONENTS_REDIRECT_MANAGER_EDIT'); + } +} diff --git a/administrator/components/com_redirect/views/links/index.html b/administrator/components/com_redirect/views/links/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_redirect/views/links/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_redirect/views/links/tmpl/default.php b/administrator/components/com_redirect/views/links/tmpl/default.php new file mode 100644 index 0000000..b31567d --- /dev/null +++ b/administrator/components/com_redirect/views/links/tmpl/default.php @@ -0,0 +1,134 @@ +escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +?> + +
    +sidebar)) : ?> +
    + sidebar; ?> +
    +
    + +
    + +
    + +
    + + +
    +
    + + pagination->getLimitBox(); ?> +
    +
    +
    + enabled) : ?> +
    + √ó + +
    + +
    + √ó + +
    + + + + + + + + + + + + + + + + + + + items as $i => $item) : + $canCreate = $user->authorise('core.create', 'com_redirect'); + $canEdit = $user->authorise('core.edit', 'com_redirect'); + $canChange = $user->authorise('core.edit.state', 'com_redirect'); + ?> + + + + + + + + + + +
    + + + + + + + + + + + +
    + pagination->getListFooter(); ?> +
    + id); ?> + + published, $i); ?> + + + escape(str_replace(JUri::root(), '', $item->old_url)); ?> + + escape(str_replace(JUri::root(), '', $item->old_url)); ?> + + + escape($item->new_url); ?> + + escape($item->referer); ?> + + created_date, JText::_('DATE_FORMAT_LC4')); ?> + + id; ?> +
    + + items)) : ?> + loadTemplate('addform'); ?> + + + + + + + +
    + diff --git a/administrator/components/com_redirect/views/links/tmpl/default_addform.php b/administrator/components/com_redirect/views/links/tmpl/default_addform.php new file mode 100644 index 0000000..c615008 --- /dev/null +++ b/administrator/components/com_redirect/views/links/tmpl/default_addform.php @@ -0,0 +1,39 @@ + +
    +
    +
    + + + +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    +
    +
    diff --git a/administrator/components/com_redirect/views/links/tmpl/index.html b/administrator/components/com_redirect/views/links/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_redirect/views/links/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_redirect/views/links/view.html.php b/administrator/components/com_redirect/views/links/view.html.php new file mode 100644 index 0000000..eed25c4 --- /dev/null +++ b/administrator/components/com_redirect/views/links/view.html.php @@ -0,0 +1,116 @@ +enabled = RedirectHelper::isEnabled(); + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + $state = $this->get('State'); + $canDo = RedirectHelper::getActions(); + + JToolbarHelper::title(JText::_('COM_REDIRECT_MANAGER_LINKS'), 'redirect'); + if ($canDo->get('core.create')) + { + JToolbarHelper::addNew('link.add'); + } + if ($canDo->get('core.edit')) + { + JToolbarHelper::editList('link.edit'); + } + if ($canDo->get('core.edit.state')) + { + if ($state->get('filter.state') != 2){ + JToolbarHelper::divider(); + JToolbarHelper::publish('links.publish', 'JTOOLBAR_ENABLE', true); + JToolbarHelper::unpublish('links.unpublish', 'JTOOLBAR_DISABLE', true); + } + if ($state->get('filter.state') != -1 ) + { + JToolbarHelper::divider(); + if ($state->get('filter.state') != 2) + { + JToolbarHelper::archiveList('links.archive'); + } + elseif ($state->get('filter.state') == 2) + { + JToolbarHelper::unarchiveList('links.publish', 'JTOOLBAR_UNARCHIVE'); + } + } + } + if ($state->get('filter.state') == -2 && $canDo->get('core.delete')) + { + JToolbarHelper::deleteList('', 'links.delete', 'JTOOLBAR_EMPTY_TRASH'); + JToolbarHelper::divider(); + } elseif ($canDo->get('core.edit.state')) + { + JToolbarHelper::trash('links.trash'); + JToolbarHelper::divider(); + } + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_redirect'); + JToolbarHelper::divider(); + } + JToolbarHelper::help('JHELP_COMPONENTS_REDIRECT_MANAGER'); + + JHtmlSidebar::setAction('index.php?option=com_redirect&view=links'); + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_state', + JHtml::_('select.options', RedirectHelper::publishedOptions(), 'value', 'text', $this->state->get('filter.state'), true) + ); + } +} diff --git a/administrator/components/com_search/access.xml b/administrator/components/com_search/access.xml new file mode 100644 index 0000000..2c9a44e --- /dev/null +++ b/administrator/components/com_search/access.xml @@ -0,0 +1,8 @@ + + +
    + + + +
    +
    diff --git a/administrator/components/com_search/config.xml b/administrator/components/com_search/config.xml new file mode 100644 index 0000000..bebb37f --- /dev/null +++ b/administrator/components/com_search/config.xml @@ -0,0 +1,72 @@ + + +
    + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    +
    diff --git a/administrator/components/com_search/controller.php b/administrator/components/com_search/controller.php new file mode 100644 index 0000000..c417e00 --- /dev/null +++ b/administrator/components/com_search/controller.php @@ -0,0 +1,45 @@ +input->get('view', 'searches')); + + parent::display(); + } +} diff --git a/administrator/components/com_search/controllers/index.html b/administrator/components/com_search/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_search/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_search/controllers/searches.php b/administrator/components/com_search/controllers/searches.php new file mode 100644 index 0000000..cab8be0 --- /dev/null +++ b/administrator/components/com_search/controllers/searches.php @@ -0,0 +1,40 @@ +getModel('Searches'); + + if (!$model->reset()) + { + JError::raiseWarning(500, $model->getError()); + } + + $this->setRedirect('index.php?option=com_search&view=searches'); + } +} diff --git a/administrator/components/com_search/helpers/index.html b/administrator/components/com_search/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_search/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_search/helpers/search.php b/administrator/components/com_search/helpers/search.php new file mode 100644 index 0000000..18ecf60 --- /dev/null +++ b/administrator/components/com_search/helpers/search.php @@ -0,0 +1,294 @@ +set($action->name, $user->authorise($action->name, $assetName)); + } + + return $result; + } + + public static function santiseSearchWord(&$searchword, $searchphrase) + { + $ignored = false; + + $lang = JFactory::getLanguage(); + $tag = $lang->getTag(); + $search_ignore = $lang->getIgnoredSearchWords(); + + // Deprecated in 1.6 use $lang->getIgnoredSearchWords instead + $ignoreFile = $lang->getLanguagePath() . '/' . $tag . '/' . $tag . '.ignore.php'; + + if (file_exists($ignoreFile)) + { + include $ignoreFile; + } + + // Check for words to ignore + $aterms = explode(' ', JString::strtolower($searchword)); + + // First case is single ignored word + if (count($aterms) == 1 && in_array(JString::strtolower($searchword), $search_ignore)) + { + $ignored = true; + } + + // Filter out search terms that are too small + $lower_limit = $lang->getLowerLimitSearchWord(); + + foreach ($aterms as $aterm) + { + if (JString::strlen($aterm) < $lower_limit) + { + $search_ignore[] = $aterm; + } + } + + // Next is to remove ignored words from type 'all' or 'any' (not exact) searches with multiple words + if (count($aterms) > 1 && $searchphrase != 'exact') + { + $pruned = array_diff($aterms, $search_ignore); + $searchword = implode(' ', $pruned); + } + + return $ignored; + } + + /** + * @since 1.5 + */ + public static function limitSearchWord(&$searchword) + { + $restriction = false; + + $lang = JFactory::getLanguage(); + + // Limit searchword to a maximum of characters + $upper_limit = $lang->getUpperLimitSearchWord(); + + if (JString::strlen($searchword) > $upper_limit) + { + $searchword = JString::substr($searchword, 0, $upper_limit - 1); + $restriction = true; + } + + // Searchword must contain a minimum of characters + if ($searchword && JString::strlen($searchword) < $lang->getLowerLimitSearchWord()) + { + $searchword = ''; + $restriction = true; + } + + return $restriction; + } + + /** + * Logs a search term + * + * @param string $search_term The term being searched + * + * @return void + * + * @since 1.5 + * @deprecated 4.0 Use JSearchHelper::logSearch() instead + */ + public static function logSearch($search_term) + { + JLog::add(__METHOD__ . '() is deprecated, use JSearchHelper::logSearch() instead.', JLog::WARNING, 'deprecated'); + + JSearchHelper::logSearch($search_term, 'com_search'); + } + + /** + * Prepares results from search for display + * + * @param string $text The source string + * @param string $searchword The searchword to select around + * + * @return string + * + * @since 1.5 + */ + public static function prepareSearchContent($text, $searchword) + { + // Strips tags won't remove the actual jscript + $text = preg_replace("']*>.*?'si", "", $text); + $text = preg_replace('/{.+?}/', '', $text); + + // $text = preg_replace('/]*>([^<]+)<\/a>/is','\2', $text); + + // Replace line breaking tags with whitespace + $text = preg_replace("'<(br[^/>]*?/|hr[^/>]*?/|/(div|h[1-6]|li|p|td))>'si", ' ', $text); + + return self::_smartSubstr(strip_tags($text), $searchword); + } + + /** + * Checks an object for search terms (after stripping fields of HTML) + * + * @param object $object The object to check + * @param string $searchTerm Search words to check for + * @param array $fields List of object variables to check against + * + * @return boolean True if searchTerm is in object, false otherwise + */ + public static function checkNoHtml($object, $searchTerm, $fields) + { + $searchRegex = array( + '#]*>.*?#si', + '#]*>.*?#si', + '##si', + '#<[^>]*>#i' + ); + $terms = explode(' ', $searchTerm); + + if (empty($fields)) + { + return false; + } + + foreach ($fields as $field) + { + if (!isset($object->$field)) + { + continue; + } + + $text = self::remove_accents($object->$field); + + foreach ($searchRegex as $regex) + { + $text = preg_replace($regex, '', $text); + } + + foreach ($terms as $term) + { + $term = self::remove_accents($term); + + if (JString::stristr($text, $term) !== false) + { + return true; + } + } + } + + return false; + } + + /** + * Transliterates given text to ASCII//TRANSLIT. + * Simulates glibc transliteration style even if libiconv is used by PHP + * + * @param string $str String to remove accents from + * + * @return string + * + * @since 3.2 + */ + public static function remove_accents($str) + { + setlocale(LC_ALL, "en_GB.UTF-8"); + $str = iconv("UTF-8", "ASCII//TRANSLIT//IGNORE", $str); + //TODO: remove other prefixes as well? + return preg_replace("/[\"'^]([a-z])/ui", '\1', $str); + } + + /** + * returns substring of characters around a searchword + * + * @param string $text The source string + * @param integer $searchword Number of chars to return + * + * @return string + * + * @since 1.5 + */ + public static function _smartSubstr($text, $searchword) + { + $lang = JFactory::getLanguage(); + $length = $lang->getSearchDisplayedCharactersNumber(); + $ltext = self::remove_accents($text); + $textlen = JString::strlen($ltext); + $lsearchword = JString::strtolower(self::remove_accents($searchword)); + $wordfound = false; + $pos = 0; + + while ($wordfound === false && $pos < $textlen) + { + if (($wordpos = @JString::strpos($ltext, ' ', $pos + $length)) !== false) + { + $chunk_size = $wordpos - $pos; + } + else + { + $chunk_size = $length; + } + + $chunk = JString::substr($ltext, $pos, $chunk_size); + $wordfound = JString::strpos(JString::strtolower($chunk), $lsearchword); + + if ($wordfound === false) + { + $pos += $chunk_size + 1; + } + } + + if ($wordfound !== false) + { + return (($pos > 0) ? '... ' : '') . JString::substr($text, $pos, $chunk_size) . ' ...'; + } + else + { + if (($wordpos = @JString::strpos($text, ' ', $length)) !== false) + { + return JString::substr($text, 0, $wordpos) . ' ...'; + } + else + { + return JString::substr($text, 0, $length); + } + } + } +} diff --git a/administrator/components/com_search/helpers/site.php b/administrator/components/com_search/helpers/site.php new file mode 100644 index 0000000..1adefc6 --- /dev/null +++ b/administrator/components/com_search/helpers/site.php @@ -0,0 +1,41 @@ + diff --git a/administrator/components/com_search/models/index.html b/administrator/components/com_search/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_search/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_search/models/searches.php b/administrator/components/com_search/models/searches.php new file mode 100644 index 0000000..87101c1 --- /dev/null +++ b/administrator/components/com_search/models/searches.php @@ -0,0 +1,195 @@ +getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $showResults = $this->getUserStateFromRequest($this->context . '.filter.results', 'filter_results', null, 'int'); + $this->setState('filter.results', $showResults); + + // Load the parameters. + $params = JComponentHelper::getParams('com_search'); + $this->setState('params', $params); + + // List state information. + parent::populateState('a.hits', 'asc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + * @since 1.6 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.results'); + + return parent::getStoreId($id); + } + + /** + * Build an SQL query to load the list data. + * + * @return JDatabaseQuery + * @since 1.6 + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.*' + ) + ); + $query->from($db->quoteName('#__core_log_searches') . ' AS a'); + + // Filter by access level. + if ($access = $this->getState('filter.access')) + { + $query->where('a.access = ' . (int) $access); + } + + // Filter by search in title + $search = $this->getState('filter.search'); + if (!empty($search)) + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('a.search_term LIKE ' . $search); + } + + // Add the list ordering clause. + $query->order($db->escape($this->getState('list.ordering', 'a.hits')) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))); + + //echo nl2br(str_replace('#__','jos_',$query)); + return $query; + } + + /** + * Override the parnet getItems to inject optional data. + * + * @return mixed An array of objects on success, false on failure. + * @since 1.6 + */ + public function getItems() + { + $items = parent::getItems(); + + // Determine if number of results for search item should be calculated + // by default it is `off` as it is highly query intensive + if ($this->getState('filter.results')) + { + JPluginHelper::importPlugin('search'); + $app = JFactory::getApplication(); + + if (!class_exists('JSite')) + { + // This fools the routers in the search plugins into thinking it's in the frontend + JLoader::register('JSite', JPATH_COMPONENT . '/helpers/site.php'); + } + + foreach ($items as &$item) + { + $results = $app->triggerEvent('onContentSearch', array($item->search_term)); + $item->returns = 0; + foreach ($results as $result) + { + $item->returns += count($result); + } + } + } + + return $items; + } + + /** + * Method to reset the seach log table. + * + * @return boolean + * @since 1.6 + */ + public function reset() + { + $db = $this->getDbo(); + $db->setQuery( + 'DELETE FROM #__core_log_searches' + ); + + try + { + $db->execute(); + } + catch (RuntimeException $e) + { + $this->setError($e->getMessage()); + return false; + } + + return true; + } +} diff --git a/administrator/components/com_search/search.php b/administrator/components/com_search/search.php new file mode 100644 index 0000000..f19a8dd --- /dev/null +++ b/administrator/components/com_search/search.php @@ -0,0 +1,19 @@ +authorise('core.manage', 'com_search')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$controller = JControllerLegacy::getInstance('Search'); +$controller->execute(JFactory::getApplication()->input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_search/search.xml b/administrator/components/com_search/search.xml new file mode 100644 index 0000000..428efcb --- /dev/null +++ b/administrator/components/com_search/search.xml @@ -0,0 +1,43 @@ + + + com_search + Joomla! Project + April 2006 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + + GNU General Public License version 2 or later; see + LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + COM_SEARCH_XML_DESCRIPTION + + + controller.php + index.html + router.php + search.php + models + views + + + language/en-GB.com_search.ini + + + Search + + config.xml + controller.php + index.html + search.php + controllers + helpers + models + views + + + language/en-GB.com_search.ini + language/en-GB.com_search.sys.ini + + + diff --git a/administrator/components/com_search/views/index.html b/administrator/components/com_search/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_search/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_search/views/searches/index.html b/administrator/components/com_search/views/searches/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_search/views/searches/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_search/views/searches/tmpl/default.php b/administrator/components/com_search/views/searches/tmpl/default.php new file mode 100644 index 0000000..67d5c57 --- /dev/null +++ b/administrator/components/com_search/views/searches/tmpl/default.php @@ -0,0 +1,108 @@ +escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$canDo = SearchHelper::getActions(); +?> +
    +
    + + +
    + + pagination->getLimitBox(); ?> +
    +
    + + state->get('filter.results')) : ?> + + + + + + + +
    +
    +
    + enabled) : ?> +
    + × + +
    + +
    + × + +
    + + + + + + + + + + + + + + + + items as $i => $item) : ?> + + + + + + + +
    + + + + + +
    + pagination->getListFooter(); ?> +
    + escape($item->search_term); ?> + + hits; ?> + + state->get('filter.results')) : ?> + returns; ?> + + + +
    +
    + + + + + +
    +
    diff --git a/administrator/components/com_search/views/searches/tmpl/index.html b/administrator/components/com_search/views/searches/tmpl/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_search/views/searches/tmpl/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_search/views/searches/view.html.php b/administrator/components/com_search/views/searches/view.html.php new file mode 100644 index 0000000..df28bc5 --- /dev/null +++ b/administrator/components/com_search/views/searches/view.html.php @@ -0,0 +1,73 @@ +items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + $this->enabled = $this->state->params->get('enabled'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 1.6 + */ + protected function addToolbar() + { + $canDo = SearchHelper::getActions(); + + JToolbarHelper::title(JText::_('COM_SEARCH_MANAGER_SEARCHES'), 'search.png'); + + if ($canDo->get('core.edit.state')) + { + JToolbarHelper::custom('searches.reset', 'refresh.png', 'refresh_f2.png', 'JSEARCH_RESET', false); + } + JToolbarHelper::divider(); + if ($canDo->get('core.admin')) + { + JToolbarHelper::preferences('com_search'); + } + JToolbarHelper::divider(); + JToolbarHelper::help('JHELP_COMPONENTS_SEARCH'); + } +} diff --git a/administrator/components/com_tags/access.xml b/administrator/components/com_tags/access.xml new file mode 100644 index 0000000..36b9a3f --- /dev/null +++ b/administrator/components/com_tags/access.xml @@ -0,0 +1,11 @@ + + +
    + + + + + + +
    +
    diff --git a/administrator/components/com_tags/config.xml b/administrator/components/com_tags/config.xml new file mode 100644 index 0000000..fac87a1 --- /dev/null +++ b/administrator/components/com_tags/config.xml @@ -0,0 +1,400 @@ + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    + +
    + + + + + + +
    + +
    + + +
    +
    diff --git a/administrator/components/com_tags/controller.php b/administrator/components/com_tags/controller.php new file mode 100644 index 0000000..edc44b9 --- /dev/null +++ b/administrator/components/com_tags/controller.php @@ -0,0 +1,55 @@ +input->get('view', 'tags'); + $layout = $this->input->get('layout', 'default'); + $id = $this->input->getInt('id'); + + // Check for edit form. + if ($view == 'tag' && $layout == 'edit' && !$this->checkEditId('com_tags.edit.tag', $id)) + { + // Somehow the person just went to the form - we don't allow that. + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id)); + $this->setMessage($this->getError(), 'error'); + $this->setRedirect(JRoute::_('index.php?option=com_tags&view=tags', false)); + + return false; + } + parent::display(); + + return $this; + + } +} diff --git a/administrator/components/com_tags/controllers/index.html b/administrator/components/com_tags/controllers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_tags/controllers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_tags/controllers/tag.php b/administrator/components/com_tags/controllers/tag.php new file mode 100644 index 0000000..e7939eb --- /dev/null +++ b/administrator/components/com_tags/controllers/tag.php @@ -0,0 +1,75 @@ +authorise('core.create', 'com_tags')); + } + + /** + * Method to check if you can edit a record. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * + * @since 3.1 + */ + protected function allowEdit($data = array(), $key = 'id') + { + // Since there is no asset tracking and no categories, revert to the component permissions. + return parent::allowEdit($data, $key); + + } + + /** + * Method to run batch operations. + * + * @param object $model The model. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 3.1 + */ + public function batch($model = null) + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Set the model + $model = $this->getModel('Tag'); + + // Preset the redirect + $this->setRedirect('index.php?option=com_tags&view=tags'); + + return parent::batch($model); + } +} diff --git a/administrator/components/com_tags/controllers/tags.php b/administrator/components/com_tags/controllers/tags.php new file mode 100644 index 0000000..12a089f --- /dev/null +++ b/administrator/components/com_tags/controllers/tags.php @@ -0,0 +1,61 @@ + true)) + { + $model = parent::getModel($name, $prefix, $config); + return $model; + } + + /** + * Rebuild the nested set tree. + * + * @return boolean False on failure or error, true on success. + * + * @since 3.1 + */ + public function rebuild() + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + $this->setRedirect(JRoute::_('index.php?option=com_tags&view=tags', false)); + + $model = $this->getModel(); + + if ($model->rebuild()) { + // Rebuild succeeded. + $this->setMessage(JText::_('COM_TAGS_REBUILD_SUCCESS')); + return true; + } else { + // Rebuild failed. + $this->setMessage(JText::_('COM_TAGSS_REBUILD_FAILURE')); + return false; + } + } +} diff --git a/administrator/components/com_tags/helpers/html/index.html b/administrator/components/com_tags/helpers/html/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_tags/helpers/html/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_tags/helpers/index.html b/administrator/components/com_tags/helpers/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_tags/helpers/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_tags/helpers/tags.php b/administrator/components/com_tags/helpers/tags.php new file mode 100644 index 0000000..2d3443d --- /dev/null +++ b/administrator/components/com_tags/helpers/tags.php @@ -0,0 +1,84 @@ +load($component, JPATH_BASE, null, false, false) + || $lang->load($component, JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $component), null, false, false) + || $lang->load($component, JPATH_BASE, $lang->getDefault(), false, false) + || $lang->load($component, JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $component), $lang->getDefault(), false, false); + + } + } + } + } + + /** + * Gets a list of the actions that can be performed. + * + * @return JObject + * + * @since 3.1 + */ + public static function getActions() + { + $user = JFactory::getUser(); + $result = new JObject; + + $assetName = 'com_tags'; + $level = 'component'; + $actions = JAccess::getActions('com_tags', $level); + + foreach ($actions as $action) + { + $result->set($action->name, $user->authorise($action->name, $assetName)); + } + + return $result; + } +} diff --git a/administrator/components/com_tags/index.html b/administrator/components/com_tags/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_tags/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_tags/models/fields/index.html b/administrator/components/com_tags/models/fields/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_tags/models/fields/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_tags/models/forms/index.html b/administrator/components/com_tags/models/forms/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_tags/models/forms/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_tags/models/forms/tag.xml b/administrator/components/com_tags/models/forms/tag.xml new file mode 100644 index 0000000..2e23141 --- /dev/null +++ b/administrator/components/com_tags/models/forms/tag.xml @@ -0,0 +1,365 @@ + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
    +
    + + +
    + + + + + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/administrator/components/com_tags/models/index.html b/administrator/components/com_tags/models/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_tags/models/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_tags/models/tag.php b/administrator/components/com_tags/models/tag.php new file mode 100644 index 0000000..eb5b255 --- /dev/null +++ b/administrator/components/com_tags/models/tag.php @@ -0,0 +1,438 @@ +id)) + { + if ($record->published != -2) + { + return; + } + return parent::canDelete($record); + } + } + + /** + * Method to test whether a record can have its state changed. + * + * @param object $record A record object. + * + * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. + * + * @since 3.1 + */ + protected function canEditState($record) + { + return parent::canEditState($record); + } + + /** + * Method to get a table object, load it if necessary. + * + * @param string $type The table name. Optional. + * @param string $prefix The class prefix. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return JTable A JTable object + * + * @since 3.1 + */ + public function getTable($type = 'Tag', $prefix = 'TagsTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @return void + * + * @since 3.1 + */ + protected function populateState() + { + $app = JFactory::getApplication('administrator'); + + $parentId = $app->input->getInt('parent_id'); + $this->setState('tag.parent_id', $parentId); + + // Load the User state. + $pk = $app->input->getInt('id'); + $this->setState($this->getName() . '.id', $pk); + + // Load the parameters. + $params = JComponentHelper::getParams('com_tags'); + $this->setState('params', $params); + } + + /** + * Method to get a tag. + * + * @param integer $pk An optional id of the object to get, otherwise the id from the model state is used. + * + * @return mixed Tag data object on success, false on failure. + * + * @since 3.1 + */ + public function getItem($pk = null) + { + if ($result = parent::getItem($pk)) + { + + // Prime required properties. + if (empty($result->id)) + { + $result->parent_id = $this->getState('tag.parent_id'); + } + + // Convert the metadata field to an array. + $registry = new JRegistry; + $registry->loadString($result->metadata); + $result->metadata = $registry->toArray(); + + // Convert the images field to an array. + $registry = new JRegistry; + $registry->loadString($result->images); + $result->images = $registry->toArray(); + + // Convert the urls field to an array. + $registry = new JRegistry; + $registry->loadString($result->urls); + $result->urls = $registry->toArray(); + + // Convert the created and modified dates to local user time for display in the form. + $tz = new DateTimeZone(JFactory::getApplication()->getCfg('offset')); + + if ((int) $result->created_time) + { + $date = new JDate($result->created_time); + $date->setTimezone($tz); + $result->created_time = $date->toSql(true); + } + else + { + $result->created_time = null; + } + + if ((int) $result->modified_time) + { + $date = new JDate($result->modified_time); + $date->setTimezone($tz); + $result->modified_time = $date->toSql(true); + } + else + { + $result->modified_time = null; + } + } + + return $result; + } + + /** + * Method to get the row form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * + * @return mixed A JForm object on success, false on failure + * + * @since 3.1 + */ + public function getForm($data = array(), $loadData = true) + { + $jinput = JFactory::getApplication()->input; + + // Get the form. + $form = $this->loadForm('com_tags.tag', 'tag', array('control' => 'jform', 'load_data' => $loadData)); + if (empty($form)) + { + return false; + } + + $user = JFactory::getUser(); + if (!$user->authorise('core.edit.state', 'com_tags' . $jinput->get('id'))) + { + // Disable fields for display. + $form->setFieldAttribute('ordering', 'disabled', 'true'); + $form->setFieldAttribute('published', 'disabled', 'true'); + + // Disable fields while saving. + // The controller has already verified this is a record you can edit. + $form->setFieldAttribute('ordering', 'filter', 'unset'); + $form->setFieldAttribute('published', 'filter', 'unset'); + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * + * @since 3.1 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_tags.edit.tag.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + } + + $this->preprocessData('com_tags.tag', $data); + + return $data; + } + + /** + * Method to preprocess the form. + * + * @param JForm $form A JForm object. + * @param mixed $data The data expected for the form. + * @param string $group The name of the plugin group to import. + * + * @return void + * + * @see JFormField + * @since 3.1 + * @throws Exception if there is an error in the form event. + */ + protected function preprocessForm(JForm $form, $data, $group = 'content') + { + // Trigger the default form events. + parent::preprocessForm($form, $data, $group); + } + + /** + * Method to save the form data. + * + * @param array $data The form data. + * + * @return boolean True on success. + * + * @since 3.1 + */ + public function save($data) + { + $dispatcher = JEventDispatcher::getInstance(); + $table = $this->getTable(); + $input = JFactory::getApplication()->input; + $pk = (!empty($data['id'])) ? $data['id'] : (int) $this->getState($this->getName() . '.id'); + $isNew = true; + + // Include the content plugins for the on save events. + JPluginHelper::importPlugin('content'); + + // Load the row if saving an existing tag. + if ($pk > 0) + { + $table->load($pk); + $isNew = false; + } + + // Set the new parent id if parent id not matched OR while New/Save as Copy . + if ($table->parent_id != $data['parent_id'] || $data['id'] == 0) + { + $table->setLocation($data['parent_id'], 'last-child'); + } + + if (isset($data['images']) && is_array($data['images'])) + { + $registry = new JRegistry; + $registry->loadArray($data['images']); + $data['images'] = (string) $registry; + } + + if (isset($data['urls']) && is_array($data['urls'])) + { + $registry = new JRegistry; + $registry->loadArray($data['urls']); + $data['urls'] = (string) $registry; + } + + // Alter the title for save as copy + if ($input->get('task') == 'save2copy') + { + list($title, $alias) = $this->generateNewTitle($data['parent_id'], $data['alias'], $data['title']); + $data['title'] = $title; + $data['alias'] = $alias; + } + + // Bind the data. + if (!$table->bind($data)) + { + $this->setError($table->getError()); + return false; + } + + // Bind the rules. + if (isset($data['rules'])) + { + $rules = new JAccessRules($data['rules']); + $table->setRules($rules); + } + + // Check the data. + if (!$table->check()) + { + $this->setError($table->getError()); + return false; + } + + // Trigger the onContentBeforeSave event. + $result = $dispatcher->trigger($this->event_before_save, array($this->option . '.' . $this->name, &$table, $isNew)); + if (in_array(false, $result, true)) + { + $this->setError($table->getError()); + return false; + } + + // Store the data. + if (!$table->store()) + { + $this->setError($table->getError()); + return false; + } + + // Trigger the onContentAfterSave event. + $dispatcher->trigger($this->event_after_save, array($this->option . '.' . $this->name, &$table, $isNew)); + + // Rebuild the path for the tag: + if (!$table->rebuildPath($table->id)) + { + $this->setError($table->getError()); + return false; + } + + // Rebuild the paths of the tag's children: + if (!$table->rebuild($table->id, $table->lft, $table->level, $table->path)) + { + $this->setError($table->getError()); + + return false; + } + + $this->setState($this->getName() . '.id', $table->id); + + // Clear the cache + $this->cleanCache(); + + return true; + } + + /** + * Method rebuild the entire nested set tree. + * + * @return boolean False on failure or error, true otherwise. + * + * @since 3.1 + */ + public function rebuild() + { + // Get an instance of the table object. + $table = $this->getTable(); + + if (!$table->rebuild()) + { + $this->setError($table->getError()); + return false; + } + + // Clear the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to save the reordered nested set tree. + * First we save the new order values in the lft values of the changed ids. + * Then we invoke the table rebuild to implement the new ordering. + * + * @param array $idArray An array of primary key ids. + * @param integer $lft_array The lft value + * + * @return boolean False on failure or error, True otherwise + * + * @since 3.1 + */ + public function saveorder($idArray = null, $lft_array = null) + { + // Get an instance of the table object. + $table = $this->getTable(); + + if (!$table->saveorder($idArray, $lft_array)) + { + $this->setError($table->getError()); + return false; + } + + // Clear the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to change the title & alias. + * + * @param integer $parent_id The id of the parent. + * @param string $alias The alias. + * @param string $title The title. + * + * @return array Contains the modified title and alias. + * + * @since 3.1 + */ + protected function generateNewTitle($parent_id, $alias, $title) + { + // Alter the title & alias + $table = $this->getTable(); + while ($table->load(array('alias' => $alias, 'parent_id' => $parent_id))) + { + $title = ($table->title != $title) ? $title : JString::increment($title); + $alias = JString::increment($alias, 'dash'); + } + + return array($title, $alias); + } +} diff --git a/administrator/components/com_tags/models/tags.php b/administrator/components/com_tags/models/tags.php new file mode 100644 index 0000000..570d344 --- /dev/null +++ b/administrator/components/com_tags/models/tags.php @@ -0,0 +1,312 @@ +context; + + $search = $this->getUserStateFromRequest($context . '.search', 'filter_search'); + $this->setState('filter.search', $search); + + $level = $this->getUserStateFromRequest($context . '.filter.level', 'filter_level', 0, 'int'); + $this->setState('filter.level', $level); + + $access = $this->getUserStateFromRequest($context . '.filter.access', 'filter_access', 0, 'int'); + $this->setState('filter.access', $access); + + $published = $this->getUserStateFromRequest($context . '.filter.published', 'filter_published', ''); + $this->setState('filter.published', $published); + + $language = $this->getUserStateFromRequest($context . '.filter.language', 'filter_language', ''); + $this->setState('filter.language', $language); + + // Load the parameters. + $params = JComponentHelper::getParams('com_tags'); + $this->setState('params', $params); + + // List state information. + parent::populateState('a.lft', 'asc'); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + * @since 3.1 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.published'); + $id .= ':' . $this->getState('filter.language'); + + return parent::getStoreId($id); + } + + /** + * Method to create a query for a list of items. + * + * @return string + * + * @since 3.1 + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + $user = JFactory::getUser(); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.id, a.title, a.alias, a.note, a.published, a.access' . + ', a.checked_out, a.checked_out_time, a.created_user_id' . + ', a.path, a.parent_id, a.level, a.lft, a.rgt' . + ', a.language' + ) + ); + $query->from('#__tags AS a') + ->where('a.alias <> ' . $db->quote('root')); + + // Join over the language + $query->select('l.title AS language_title') + ->join('LEFT', $db->quoteName('#__languages') . ' AS l ON l.lang_code = a.language'); + + // Join over the users for the checked out user. + $query->select('uc.name AS editor') + ->join('LEFT', '#__users AS uc ON uc.id=a.checked_out'); + + // Join over the users for the author. + $query->select('ua.name AS author_name') + ->join('LEFT', '#__users AS ua ON ua.id = a.created_user_id') + + ->select('ug.title AS access_title') + ->join('LEFT', '#__viewlevels AS ug on ug.id = a.access'); + + // Filter on the level. + if ($level = $this->getState('filter.level')) + { + $query->where('a.level <= ' . (int) $level); + } + + // Filter by access level. + if ($access = $this->getState('filter.access')) + { + $query->where('a.access = ' . (int) $access); + } + + // Implement View Level Access + if (!$user->authorise('core.admin')) + { + $groups = implode(',', $user->getAuthorisedViewLevels()); + $query->where('a.access IN (' . $groups . ')'); + } + + // Filter by published state + $published = $this->getState('filter.published'); + if (is_numeric($published)) + { + $query->where('a.published = ' . (int) $published); + } + elseif ($published === '') + { + $query->where('(a.published IN (0, 1))'); + } + + // Filter by search in title + $search = $this->getState('filter.search'); + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + elseif (stripos($search, 'author:') === 0) + { + $search = $db->quote('%' . $db->escape(substr($search, 7), true) . '%'); + $query->where('(ua.name LIKE ' . $search . ' OR ua.username LIKE ' . $search . ')'); + } + else + { + $search = $db->quote('%' . $db->escape($search, true) . '%'); + $query->where('(a.title LIKE ' . $search . ' OR a.alias LIKE ' . $search . ' OR a.note LIKE ' . $search . ')'); + } + } + + // Filter on the language. + if ($language = $this->getState('filter.language')) + { + $query->where('a.language = ' . $db->quote($language)); + } + + // Add the list ordering clause + $listOrdering = $this->getState('list.ordering', 'a.lft'); + $listDirn = $db->escape($this->getState('list.direction', 'ASC')); + if ($listOrdering == 'a.access') + { + $query->order('a.access ' . $listDirn . ', a.lft ' . $listDirn); + } + else + { + $query->order($db->escape($listOrdering) . ' ' . $listDirn); + } + + //echo nl2br(str_replace('#__','jos_',$query)); + return $query; + } + + /** + * Method override to check-in a record or an array of record + * + * @param mixed $pks The ID of the primary key or an array of IDs + * + * @return mixed Boolean false if there is an error, otherwise the count of records checked in. + * + * @since 12.2 + */ + public function checkin($pks = array()) + { + $pks = (array) $pks; + $table = $this->getTable(); + $count = 0; + + if (empty($pks)) + { + $pks = array((int) $this->getState($this->getName() . '.id')); + } + + // Check in all items. + foreach ($pks as $pk) + { + if ($table->load($pk)) + { + + if ($table->checked_out > 0) + { + // Only attempt to check the row in if it exists. + if ($pk) + { + $user = JFactory::getUser(); + + // Get an instance of the row to checkin. + $table = $this->getTable(); + if (!$table->load($pk)) + { + $this->setError($table->getError()); + return false; + } + + // Check if this is the user having previously checked out the row. + if ($table->checked_out > 0 && $table->checked_out != $user->get('id') && !$user->authorise('core.admin', 'com_checkin')) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_CHECKIN_USER_MISMATCH')); + return false; + } + + // Attempt to check the row in. + if (!$table->checkin($pk)) + { + $this->setError($table->getError()); + return false; + } + } + + $count++; + } + } + else + { + $this->setError($table->getError()); + + return false; + } + } + + return $count; + } + + /** + * Method to get a table object, load it if necessary. + * + * @param string $type The table name. Optional. + * @param string $prefix The class prefix. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return JTable A JTable object + * + * @since 3.1 + */ + public function getTable($type = 'Tag', $prefix = 'TagsTable', $config = array()) + { + return JTable::getInstance($type, $prefix, $config); + } +} diff --git a/administrator/components/com_tags/tables/index.html b/administrator/components/com_tags/tables/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_tags/tables/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_tags/tables/tag.php b/administrator/components/com_tags/tables/tag.php new file mode 100644 index 0000000..547d097 --- /dev/null +++ b/administrator/components/com_tags/tables/tag.php @@ -0,0 +1,205 @@ +loadArray($array['params']); + $array['params'] = (string) $registry; + } + + if (isset($array['metadata']) && is_array($array['metadata'])) + { + $registry = new JRegistry; + $registry->loadArray($array['metadata']); + $array['metadata'] = (string) $registry; + } + + if (isset($array['urls']) && $array['urls']) + { + $registry = new JRegistry; + $registry->loadArray($array['urls']); + $array['urls'] = (string) $registry; + } + + if (isset($array['images']) && is_array($array['images'])) + { + $registry = new JRegistry; + $registry->loadArray($array['images']); + $array['images'] = (string) $registry; + } + + return parent::bind($array, $ignore); + } + + /** + * Overloaded check method to ensure data integrity. + * + * @return boolean True on success. + * + * @since 3.1 + * @throws UnexpectedValueException + */ + public function check() + { + // Check for valid name. + if (trim($this->title) == '') + { + throw new UnexpectedValueException(sprintf('The title is empty')); + } + + if (empty($this->alias)) + { + $this->alias = $this->title; + } + $this->alias = JApplication::stringURLSafe($this->alias); + if (trim(str_replace('-', '', $this->alias)) == '') + { + $this->alias = JFactory::getDate()->format("Y-m-d-H-i-s"); + } + + // Check the publish down date is not earlier than publish up. + if ((int) $this->publish_down > 0 && $this->publish_down < $this->publish_up) + { + throw new UnexpectedValueException(sprintf('End publish date is before start publish date.')); + } + + // Clean up keywords -- eliminate extra spaces between phrases + // and cr (\r) and lf (\n) characters from string + if (!empty($this->metakey)) + { + // Only process if not empty + // Define array of characters to remove + $bad_characters = array("\n", "\r", "\"", "<", ">"); + // Remove bad characters + $after_clean = JString::str_ireplace($bad_characters, "", $this->metakey); + + // Create array using commas as delimiter + $keys = explode(',', $after_clean); + $clean_keys = array(); + foreach($keys as $key) + { + if (trim($key)) + { + // Ignore blank keywords + $clean_keys[] = trim($key); + } + } + + // Put array back together delimited by ", " + $this->metakey = implode(", ", $clean_keys); + } + + // Clean up description -- eliminate quotes and <> brackets + if (!empty($this->metadesc)) { + // Only process if not empty + $bad_characters = array("\"", "<", ">"); + $this->metadesc = JString::str_ireplace($bad_characters, "", $this->metadesc); + } + + return true; + } + + /** + * Overriden JTable::store to set modified data and user id. + * + * @param boolean $updateNulls True to update fields even if they are null. + * + * @return boolean True on success. + * + * @since 3.1 + */ + public function store($updateNulls = false) + { + $date = JFactory::getDate(); + $user = JFactory::getUser(); + if ($this->id) { + // Existing item + $this->modified_time = $date->toSql(); + $this->modified_user_id = $user->get('id'); + } + else + { + // New tag. A tag created and created_by field can be set by the user, + // so we don't touch either of these if they are set. + if (!(int) $this->created_time) { + $this->created_time = $date->toSql(); + } + if (empty($this->created_user_id)) { + $this->created_user_id = $user->get('id'); + } + } + + // Verify that the alias is unique + $table = JTable::getInstance('Tag', 'TagsTable'); + if ($table->load(array('alias' => $this->alias)) && ($table->id != $this->id || $this->id == 0)) + { + $this->setError(JText::_('COM_TAGS_ERROR_UNIQUE_ALIAS')); + return false; + } + return parent::store($updateNulls); + } + + /** + * Method to delete a node and, optionally, its child nodes from the table. + * + * @param integer $pk The primary key of the node to delete. + * @param boolean $children True to delete child nodes, false to move them up a level. + * + * @return boolean True on success. + * + * @since 3.1 + * @see http://docs.joomla.org/JTableNested/delete + */ + public function delete($pk = null, $children = false) + { + $return = parent::delete($pk, $children); + if ($return) + { + $helper = new JHelperTags; + $helper->tagDeleteInstances($pk); + } + return $return; + } +} diff --git a/administrator/components/com_tags/tags.php b/administrator/components/com_tags/tags.php new file mode 100644 index 0000000..d7503d9 --- /dev/null +++ b/administrator/components/com_tags/tags.php @@ -0,0 +1,23 @@ +input; + +if (!JFactory::getUser()->authorise('core.manage', 'com_tags')) +{ + return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); +} + +$task = $input->get('task'); + +$controller = JControllerLegacy::getInstance('Tags'); +$controller->execute($input->get('task')); +$controller->redirect(); diff --git a/administrator/components/com_tags/tags.xml b/administrator/components/com_tags/tags.xml new file mode 100644 index 0000000..d7017ba --- /dev/null +++ b/administrator/components/com_tags/tags.xml @@ -0,0 +1,46 @@ + + + com_tags + Joomla! Project + December 2013 + (C) 2005 - 2013 Open Source Matters. All rights reserved. + http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL + admin@joomla.org + www.joomla.org + 3.1.0 + COM_TAGS_XML_DESCRIPTION + + + controller.php + index.html + metadata.xml + newsfeeds.php + router.php + helpers + models + views + + + language/en-GB.com_tags.ini + + + + tags.php + config.xml + controller.php + index.html + controllers + helpers + models + views + + + language/en-GB.com_tags.ini + language/en-GB.com_tags.sys.ini + + com_tags + + + + + diff --git a/administrator/components/com_tags/views/index.html b/administrator/components/com_tags/views/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_tags/views/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_tags/views/tag/index.html b/administrator/components/com_tags/views/tag/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_tags/views/tag/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_tags/views/tag/tmpl/edit.php b/administrator/components/com_tags/views/tag/tmpl/edit.php new file mode 100644 index 0000000..d2aa200 --- /dev/null +++ b/administrator/components/com_tags/views/tag/tmpl/edit.php @@ -0,0 +1,214 @@ +input; + +JHtml::_('behavior.formvalidation'); +JHtml::_('behavior.keepalive'); +JHtml::_('formbehavior.chosen', 'select'); + +// Create shortcut to parameters. +$params = $this->state->get('params'); +$params = $params->toArray(); + +?> + + + +
    + + + +
    + +
    + 'general')); ?> + + +
    +
    + form->getLabel('title'); ?> form->getInput('title'); ?> form->getLabel('catid'); ?> form->getInput('catid'); ?> +
    + form->getInput('description'); ?> +
    +
    +
    +

    +
    + form->getLabel('images'); ?> +
    + form->getInput('images'); ?> +
    +
    + form->getGroup('images') as $field) : ?> +
    + hidden) : ?> + label; ?> + +
    + input; ?> +
    +
    + +
    +
    + + + +
    +
    +
    + form->getLabel('alias'); ?> +
    + form->getInput('alias'); ?> +
    +
    +
    +
    + form->getLabel('id'); ?> +
    +
    + form->getInput('id'); ?> +
    +
    +
    + form->getLabel('created_user_id'); ?> +
    + form->getInput('created_user_id'); ?> +
    +
    +
    + form->getLabel('created_by_alias'); ?> +
    + form->getInput('created_by_alias'); ?> +
    +
    +
    + form->getLabel('created_time'); ?> +
    + form->getInput('created_time'); ?> +
    +
    +
    +
    +
    + form->getLabel('publish_up'); ?> +
    + form->getInput('publish_up'); ?> +
    +
    +
    + form->getLabel('publish_down'); ?> +
    + form->getInput('publish_down'); ?> +
    +
    + item->modified_user_id) : ?> +
    + form->getLabel('modified_user_id'); ?> +
    + form->getInput('modified_user_id'); ?> +
    +
    +
    + form->getLabel('modified_time'); ?> +
    + form->getInput('modified_time'); ?> +
    +
    + + + item->version) : ?> +
    + form->getLabel('version'); ?> +
    + form->getInput('version'); ?> +
    +
    + + + item->hits) : ?> +
    +
    + form->getLabel('hits'); ?> +
    +
    + form->getInput('hits'); ?> +
    +
    + +
    +
    + + + + loadTemplate('options'); ?> + + + + loadTemplate('metadata'); ?> + +
    + + +
    + + +
    +

    +
    +
    +
    +
    + form->getValue('title'); ?> +
    +
    +
    + form->getLabel('parent_id'); ?> +
    + form->getInput('parent_id'); ?> +
    +
    +
    + form->getLabel('published'); ?> +
    + form->getInput('published'); ?> +
    +
    +
    + form->getLabel('access'); ?> +
    + form->getInput('access'); ?> +
    +
    +
    + form->getLabel('language'); ?> +
    + form->getInput('language'); ?> +
    +
    +
    +
    + +
    + diff --git a/administrator/components/com_tags/views/tag/tmpl/edit_metadata.php b/administrator/components/com_tags/views/tag/tmpl/edit_metadata.php new file mode 100644 index 0000000..1e9afd2 --- /dev/null +++ b/administrator/components/com_tags/views/tag/tmpl/edit_metadata.php @@ -0,0 +1,33 @@ + +
    + form->getLabel('metadesc'); ?> +
    + form->getInput('metadesc'); ?> +
    +
    +
    + form->getLabel('metakey'); ?> +
    + form->getInput('metakey'); ?> +
    +
    +form->getGroup('metadata') as $field): ?> +
    + hidden): ?> + label; ?> + +
    + input; ?> +
    +
    + diff --git a/administrator/components/com_tags/views/tag/tmpl/edit_options.php b/administrator/components/com_tags/views/tag/tmpl/edit_options.php new file mode 100644 index 0000000..27caccf --- /dev/null +++ b/administrator/components/com_tags/views/tag/tmpl/edit_options.php @@ -0,0 +1,63 @@ + + 'collapse0')); + $fieldSets = $this->form->getFieldsets('params'); + $i = 0; + + foreach ($fieldSets as $name => $fieldSet) : + $label = !empty($fieldSet->label) ? $fieldSet->label : 'COM_TAGS_'.$name.'_FIELDSET_LABEL'; + echo JHtml::_('bootstrap.addSlide', 'categoryOptions', JText::_($label), 'collapse' . $i++); + if (isset($fieldSet->description) && trim($fieldSet->description)) : + echo '

    '.$this->escape(JText::_($fieldSet->description)).'

    '; + endif; + ?> + form->getFieldset($name) as $field) : ?> +
    +
    + label; ?> +
    +
    + input; ?> +
    +
    + + + +
    +
    + form->getLabel('note'); ?> +
    +
    + form->getInput('note'); ?> +
    +
    +
    +
    + form->getLabel('tag_layout'); ?> +
    +
    + form->getInput('tag_layout'); ?> +
    +
    +
    +
    + form->getLabel('tag_link_class'); ?> +
    +
    + form->getInput('tag_link_class'); ?> +
    +
    + diff --git a/administrator/components/com_tags/views/tag/view.html.php b/administrator/components/com_tags/views/tag/view.html.php new file mode 100644 index 0000000..f6af678 --- /dev/null +++ b/administrator/components/com_tags/views/tag/view.html.php @@ -0,0 +1,112 @@ +form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + $this->canDo = TagsHelper::getActions($this->state->get('tags.component')); + $input = JFactory::getApplication()->input; + + // Check for errors. + if (count($errors = $this->get('Errors'))) { + JError::raiseError(500, implode("\n", $errors)); + return false; + } + + $input->set('hidemainmenu', true); + $this->addToolbar(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @since 3.1 + */ + protected function addToolbar() + { + $user = JFactory::getUser(); + $userId = $user->get('id'); + + $isNew = ($this->item->id == 0); + $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $userId); + + // Need to load the menu language file as mod_menu hasn't been loaded yet. + $lang = JFactory::getLanguage(); + $lang->load('com_tags', JPATH_BASE, null, false, false) + || $lang->load('com_tags', JPATH_ADMINISTRATOR.'/components/com_tags', null, false, false) + || $lang->load('com_tags', JPATH_BASE, $lang->getDefault(), false, false) + || $lang->load('com_tags', JPATH_ADMINISTRATOR.'/components/com_tags', $lang->getDefault(), false, false); + + // Load the tags helper. + require_once JPATH_COMPONENT.'/helpers/tags.php'; + + // Get the results for each action. + $canDo = TagsHelper::getActions('com_tags', $this->item->id); + + $title = JText::_('COM_TAGS_BASE_'.($isNew?'ADD':'EDIT').'_TITLE'); + + // Prepare the toolbar. + JToolbarHelper::title($title, 'tags.png'); + + // For new records, check the create permission. + if ($isNew) + { + JToolbarHelper::apply('tag.apply'); + JToolbarHelper::save('tag.save'); + JToolbarHelper::save2new('tag.save2new'); + } + + // If not checked out, can save the item. + elseif (!$checkedOut && ($canDo->get('core.edit') || ($canDo->get('core.edit.own') && $this->item->created_user_id == $userId))) { + JToolbarHelper::apply('tag.apply'); + JToolbarHelper::save('tag.save'); + if ($canDo->get('core.create')) { + JToolbarHelper::save2new('tag.save2new'); + } + } + + // If an existing item, can save to a copy. + if (!$isNew && $canDo->get('core.create')) { + JToolbarHelper::save2copy('tag.save2copy'); + } + + if (empty($this->item->id)) { + JToolbarHelper::cancel('tag.cancel'); + } + else { + JToolbarHelper::cancel('tag.cancel', 'JTOOLBAR_CLOSE'); + } + JToolbarHelper::help('JHELP_COMPONENTS_TAGS_MANAGER_EDIT'); + JToolbarHelper::divider(); + + } +} diff --git a/administrator/components/com_tags/views/tags/index.html b/administrator/components/com_tags/views/tags/index.html new file mode 100644 index 0000000..2efb97f --- /dev/null +++ b/administrator/components/com_tags/views/tags/index.html @@ -0,0 +1 @@ + diff --git a/administrator/components/com_tags/views/tags/tmpl/default.php b/administrator/components/com_tags/views/tags/tmpl/default.php new file mode 100644 index 0000000..76ca910 --- /dev/null +++ b/administrator/components/com_tags/views/tags/tmpl/default.php @@ -0,0 +1,232 @@ +get('id'); +$listOrder = $this->escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +$ordering = ($listOrder == 'a.lft'); +$canOrder = $user->authorise('core.edit.state', 'com_tags'); +$saveOrder = ($listOrder == 'a.lft' && $listDirn == 'asc'); +if ($saveOrder) +{ + $saveOrderingUrl = 'index.php?option=com_tags&task=tags.saveOrderAjax'; + JHtml::_('sortablelist.sortable', 'categoryList', 'adminForm', strtolower($listDirn), $saveOrderingUrl, false, true); +} +$sortFields = $this->getSortFields(); +?> + +
    +sidebar)): ?> +
    + sidebar; ?> +
    +
    + +
    + +
    + +
    + + +
    +
    + + pagination->getLimitBox(); ?> +
    +
    + + +
    +
    + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + items as $i => $item) : + $orderkey = array_search($item->id, $this->ordering[$item->parent_id]); + $canCreate = $user->authorise('core.create', 'com_tags'); + $canEdit = $user->authorise('core.edit', 'com_tags'); + $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id')|| $item->checked_out == 0; + $canChange = $user->authorise('core.edit.state', 'com_tags') && $canCheckin; + // Get the parents of item for sorting + if ($item->level > 1) + { + $parentsStr = ""; + $_currentParentId = $item->parent_id; + $parentsStr = " ".$_currentParentId; + for ($j = 0; $j < $item->level; $j++) + { + foreach ($this->ordering as $k => $v) + { + $v = implode("-", $v); + $v = "-" . $v . "-"; + if (strpos($v, "-" . $_currentParentId . "-") !== false) + { + $parentsStr .= " " . $k; + $_currentParentId = $k; + break; + } + } + } + } + else + { + $parentsStr = ""; + } + ?> + + + + + + + + + + + + +
    + ', 'a.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING'); ?> + + + + + + + + + + state->get('list.direction'), $this->state->get('list.ordering')); ?> + + +
    + pagination->getListFooter(); ?> +
    + + + + + + + + + id); ?> + + published, $i, 'tags.', $canChange);?> + + level > 0): ?> + —', $item->level - 1) ?> + + checked_out) : ?> + editor, $item->checked_out_time, 'tags.', $canCheckin); ?> + + + + escape($item->title); ?> + + escape($item->title); ?> + + + note)) : ?> + escape($item->alias));?> + + escape($item->alias), $this->escape($item->note));?> + + + + escape($item->access_title); ?> + + language == '*') : ?> + + + language_title ? $this->escape($item->language_title) : JText::_('JUNDEFINED'); ?> + + + + id; ?> +
    + + loadTemplate('batch'); ?> + + + + + + + +
    + diff --git a/administrator/components/com_tags/views/tags/tmpl/default_batch.php b/administrator/components/com_tags/views/tags/tmpl/default_batch.php new file mode 100644 index 0000000..144271c --- /dev/null +++ b/administrator/components/com_tags/views/tags/tmpl/default_batch.php @@ -0,0 +1,41 @@ +state->get('filter.published'); +?> +