commit c76e45a0dfda5592353e74c16ff0a8ab1f65f6fe Author: Jean-Christian Denis Date: Thu Aug 26 01:06:22 2021 +0200 initial commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General +Public License instead of this License. diff --git a/_admin.php b/_admin.php new file mode 100644 index 0000000..c6f5db3 --- /dev/null +++ b/_admin.php @@ -0,0 +1,314 @@ +addItem( + __('Links shortener'), + 'plugin.php?p=kUtRL','index.php?pf=kUtRL/icon.png', + preg_match('/plugin.php\?p=kUtRL(&.*)?$/',$_SERVER['REQUEST_URI']), + $core->auth->check('admin',$core->blog->id) +); + +# Admin behaviors +if ($core->blog->settings->kUtRL->kutrl_active) +{ + $core->addBehavior('adminPostHeaders',array('adminKutrl','adminPostHeaders')); + $core->addBehavior('adminPostFormSidebar',array('adminKutrl','adminPostFormSidebar')); + $core->addBehavior('adminAfterPostUpdate',array('adminKutrl','adminAfterPostUpdate')); // update existing short url + $core->addBehavior('adminAfterPostUpdate',array('adminKutrl','adminAfterPostCreate')); // create new short url + $core->addBehavior('adminAfterPostCreate',array('adminKutrl','adminAfterPostCreate')); + $core->addBehavior('adminBeforePostDelete',array('adminKutrl','adminBeforePostDelete')); + $core->addBehavior('adminPostsActionsCombo',array('adminKutrl','adminPostsActionsCombo')); + $core->addBehavior('adminPostsActions',array('adminKutrl','adminPostsActions')); +} + +$core->addBehavior('exportFull',array('backupKutrl','exportFull')); +$core->addBehavior('exportSingle',array('backupKutrl','exportSingle')); +$core->addBehavior('importInit',array('backupKutrl','importInit')); +$core->addBehavior('importSingle',array('backupKutrl','importSingle')); +$core->addBehavior('importFull',array('backupKutrl','importFull')); + +# Admin behaviors class +class adminKutrl +{ + public static function adminPostHeaders() + { + return dcPage::jsLoad('index.php?pf=kUtRL/js/admin.js'); + } + + public static function adminPostFormSidebar($post) + { + global $core; + $s = $core->blog->settings->kUtRL; + + if (!$s->kutrl_active || !$s->kutrl_admin_service) return; + + if (null === ($kut = kutrl::quickPlace('admin'))) return; + + if ($post) + { + $post_url = $post->getURL(); + $rs = $kut->isKnowUrl($post_url); + } + else + { + $post_url = ''; + $rs = false; + } + + echo + '

'.__('Short link').'

'. + '
'. + form::hidden(array('kutrl_old_post_url'),$post_url); + + if (!$rs) + { + if (empty($_POST['kutrl_old_post_url']) && $s->kutrl_admin_entry_default) + { + $chk = true; + } + else + { + $chk = !empty($_POST['kutrl_create']); + } + echo + '

'; + + if ($kut->allow_custom_hash) + { + echo + '

'. + '

'; + } + } + else + { + $count = $rs->counter; + if ($count == 0) + { + $title = __('never followed'); + } + elseif ($count == 1) + { + $title = __('followed one time'); + } + else + { + $title = sprintf(__('followed %s times'),$count); + } + $href = $kut->url_base.$rs->hash; + + echo + '

'. + '

'.$href.'

'; + } + echo '
'; + } + + public static function adminAfterPostUpdate($cur,$post_id) + { + global $core; + $s = $core->blog->settings->kUtRL; + + # Create: see adminAfterPostCreate + if (!empty($_POST['kutrl_create']) || !$s->kutrl_active) return; + + if (null === ($kut = kutrl::quickPlace('admin'))) return; + + if (empty($_POST['kutrl_old_post_url'])) return; + + $old_post_url = $_POST['kutrl_old_post_url']; + + if (!($rs = $kut->isKnowUrl($old_post_url))) return; + + $rs = $core->blog->getPosts(array('post_id'=>$post_id)); + $title = html::escapeHTML($rs->post_title); + + if ($rs->isEmpty()) return; + + $new_post_url = $rs->getURL(); + + # Delete + if (!empty($_POST['kutrl_delete'])) + { + $kut->remove($old_post_url); + } + # Update + else + { + if ($old_post_url == $new_post_url) return; + + $kut->remove($old_post_url); + + $rs = $kut->hash($new_post_url,$custom); // better to update (not yet implemented) + $url = $kut->url_base.$rs->hash; + + # ex: Send new url to messengers + if (!empty($rs)) + { + $core->callBehavior('adminAfterKutrlCreate',$core,$rs,$title); + } + } + } + + public static function adminAfterPostCreate($cur,$post_id) + { + global $core; + $s = $core->blog->settings->kUtRL; + + if (empty($_POST['kutrl_create']) || !$s->kutrl_active) return; + + if (null === ($kut = kutrl::quickPlace('admin'))) return; + + $rs = $core->blog->getPosts(array('post_id'=>$post_id)); + $title = html::escapeHTML($rs->post_title); + + if ($rs->isEmpty()) return; + + $custom = !empty($_POST['kutrl_create_custom']) && $kut->allow_custom_hash ? + $_POST['kutrl_create_custom'] : null; + + $rs = $kut->hash($rs->getURL(),$custom); + $url = $kut->url_base.$rs->hash; + + # ex: Send new url to messengers + if (!empty($rs)) + { + $core->callBehavior('adminAfterKutrlCreate',$core,$rs,$title); + } + } + + public static function adminBeforePostDelete($post_id) + { + global $core; + $s = $core->blog->settings->kUtRL; + + if (!$s->kutrl_active) return; + + if (null === ($kut = kutrl::quickPlace('admin'))) return; + + $rs = $core->blog->getPosts(array('post_id'=>$post_id)); + + if ($rs->isEmpty()) return; + + $kut->remove($rs->getURL()); + } + + public static function adminPostsActionsCombo($args) + { + global $core; + $s = $core->blog->settings->kUtRL; + + if (!$s->kutrl_active + || !$core->auth->check('admin',$core->blog->id)) return; + + $args[0][__('kUtRL')][__('create short link')] = 'kutrl_create'; + $args[0][__('kUtRL')][__('delete short link')] = 'kutrl_delete'; + } + + public static function adminPostsActions($core,$posts,$action,$redir) + { + if ($action != 'kutrl_create' + && $action != 'kutrl_delete') return; + + $s = $core->blog->settings->kUtRL; + + if (!$s->kutrl_active) return; + + if (null === ($kut = kutrl::quickPlace('admin'))) return; + + while ($posts->fetch()) + { + $url = $posts->getURL(); + + if ($action == 'kutrl_create') + { + $kut->hash($url); + } + + if ($action == 'kutrl_delete') + { + $kut->remove($url); + } + } + $core->blog->triggerBlog(); + http::redirect($redir.'&done=1'); + } +} + +# Import/export behaviors for Import/export plugin +class backupKutrl +{ + public static function exportSingle($core,$exp,$blog_id) + { + $exp->export('kutrl', + 'SELECT kut_id, blog_id, kut_service, kut_type, '. + 'kut_hash, kut_url, kut_dt, kut_password, kut_counter '. + 'FROM '.$core->prefix.'kutrl '. + "WHERE blog_id = '".$blog_id."' " + ); + } + + public static function exportFull($core,$exp) + { + $exp->exportTable('kutrl'); + } + + public static function importInit($bk,$core) + { + $bk->cur_kutrl = $core->con->openCursor($core->prefix.'kutrl'); + $bk->kutrl = new kutrlLog($core); + } + + public static function importSingle($line,$bk,$core) + { + if ($line->__name == 'kutrl') + { + # Do nothing if str/type exists ! + if (false === $bk->kutrl->select($line->kut_url,$line->kut_hash,$line->kut_type,$line->kut_service)) + { + $bk->kutrl->insert($line->kut_url,$line->kut_hash,$line->kut_type,$line->kut_service); + } + } + } + + public static function importFull($line,$bk,$core) + { + if ($line->__name == 'kutrl') + { + $bk->cur_kutrl->clean(); + + $bk->cur_kutrl->kut_id = (integer) $line->kut_id; + $bk->cur_kutrl->blog_id = (string) $line->blog_id; + $bk->cur_kutrl->kut_service = (string) $line->kut_service; + $bk->cur_kutrl->kut_type = (string) $line->kut_type; + $bk->cur_kutrl->kut_hash = (string) $line->kut_hash; + $bk->cur_kutrl->kut_url = (string) $line->kut_url; + $bk->cur_kutrl->kut_dt = (string) $line->miniurl_dt; + $bk->cur_kutrl->kut_counter = (integer) $line->kut_counter; + $bk->cur_kutrl->kut_password = (string) $line->kut_password; + + $bk->cur_kutrl->insert(); + } + } +} +?> \ No newline at end of file diff --git a/_define.php b/_define.php new file mode 100644 index 0000000..ff63dc5 --- /dev/null +++ b/_define.php @@ -0,0 +1,13 @@ +registerModule( /* Name */ "kUtRL", /* Description*/ "Use, create and serve short url on your blog", /* Author */ "JC Denis", /* Version */ '2011.03.24', /* Permissions */ 'admin' ); ?> \ No newline at end of file diff --git a/_install.php b/_install.php new file mode 100644 index 0000000..5c04d11 --- /dev/null +++ b/_install.php @@ -0,0 +1,94 @@ +plugins->moduleInfo('kUtRL','version'); +$old_version = $core->getVersion('kUtRL'); + +# Compare versions +if (version_compare($old_version,$new_version,'>=')) {return;} + +# Install or update +try +{ + if (version_compare(str_replace("-r","-p",DC_VERSION),'2.2-alpha','<')) + { + throw new Exception('kUtRL requires Dotclear 2.2'); + } + + # Table + $t = new dbStruct($core->con,$core->prefix); + $t->kutrl + ->kut_id('bigint',0,false) + ->blog_id('varchar',32,false) + ->kut_service('varchar',32,false,"'kUtRL'") + ->kut_type('varchar',32,false) + ->kut_hash('varchar',32,false) + ->kut_url('text',0,false) + ->kut_dt('timestamp',0,false,'now()') + ->kut_password('varchar',32,true) + ->kut_counter('bigint',0,false,0) + + ->primary('pk_kutrl','kut_id') + ->index('idx_kut_blog_id','btree','blog_id') + ->index('idx_kut_hash','btree','kut_hash') + ->index('idx_kut_service','btree','kut_service') + ->index('idx_kut_type','btree','kut_type'); + + $ti = new dbStruct($core->con,$core->prefix); + $changes = $ti->synchronize($t); + + # Settings + $core->blog->settings->addNamespace('kUtRL'); + $s = $core->blog->settings->kUtRL; + $s->put('kutrl_active',false,'boolean','Enabled kutrl plugin',false,true); + $s->put('kutrl_plugin_service','default','string','Service to use to shorten links on third part plugins',false,true); + $s->put('kutrl_admin_service','local','string','Service to use to shorten links on admin',false,true); + $s->put('kutrl_tpl_service','local','string','Service to use to shorten links on template',false,true); + $s->put('kutrl_wiki_service','local','string','Service to use to shorten links on contents',false,true); + $s->put('kutrl_allow_external_url',true,'boolean','Limited short url to current blog\'s url',false,true); + $s->put('kutrl_tpl_passive',true,'boolean','Return long url on kutrl tags if kutrl is unactivate',false,true); + $s->put('kutrl_tpl_active',false,'boolean','Return short url on dotclear tags if kutrl is active',false,true); + $s->put('kutrl_admin_entry_default',true,'boolean','Create short link an new entry by default',false,true); + # Settings for "local" service + $local_css = + ".shortenkutrlwidget input { border: 1px solid #CCCCCC; }\n". + ".dc-kutrl input { border: 1px solid #CCCCCC; margin: 10px; }"; + $s->put('kutrl_srv_local_protocols','http:,https:,ftp:,ftps:,irc:','string','Allowed kutrl local service protocols',false,true); + $s->put('kutrl_srv_local_public',false,'boolean','Enabled local service public page',false,true); + $s->put('kutrl_srv_local_css',$local_css,'string','Special CSS for kutrl local service',false,true); + $s->put('kutrl_srv_local_404_active',false,'boolean','Use special 404 page on unknow urls',false,true); + # Settings for "bilbolinks" service + $s->put('kutrl_srv_bilbolinks_base','http://tux-pla.net/','string','URL of bilbolinks service',false,true); + # Settings for "YOURLS" service + $s->put('kutrl_srv_yourls_base','','string','URL of YOURLS service',false,true); + $s->put('kutrl_srv_yourls_username','','string','User name to YOURLS service',false,true); + $s->put('kutrl_srv_yourls_password','','string','User password to YOURLS service',false,true); + + # Version + $core->setVersion('kUtRL',$new_version); + + # Get dcMiniUrl records as this plugin do the same + if ($core->plugins->moduleExists('dcMiniUrl')) + { + require_once dirname(__FILE__).'/inc/patch.dcminiurl.php'; + } + return true; +} +catch (Exception $e) +{ + $core->error->add($e->getMessage()); + return false; +} +?> \ No newline at end of file diff --git a/_prepend.php b/_prepend.php new file mode 100644 index 0000000..522a43f --- /dev/null +++ b/_prepend.php @@ -0,0 +1,78 @@ +addBehavior('kutrlService',create_function(null,'return array("bilbolinks","bilbolinksKutrlService");')); +$__autoload['bitlyKutrlService'] = dirname(__FILE__).'/inc/services/class.bitly.service.php'; +$core->addBehavior('kutrlService',create_function(null,'return array("bitly","bitlyKutrlService");')); +$__autoload['customKutrlService'] = dirname(__FILE__).'/inc/services/class.custom.service.php'; +$core->addBehavior('kutrlService',create_function(null,'return array("custom","customKutrlService");')); +$__autoload['defaultKutrlService'] = dirname(__FILE__).'/inc/services/class.default.service.php'; +$core->addBehavior('kutrlService',create_function(null,'return array("default","defaultKutrlService");')); +$__autoload['googlKutrlService'] = dirname(__FILE__).'/inc/services/class.googl.service.php'; +$core->addBehavior('kutrlService',create_function(null,'return array("googl","googlKutrlService");')); +$__autoload['isgdKutrlService'] = dirname(__FILE__).'/inc/services/class.isgd.service.php'; +$core->addBehavior('kutrlService',create_function(null,'return array("isgd","isgdKutrlService");')); +$__autoload['localKutrlService'] = dirname(__FILE__).'/inc/services/class.local.service.php'; +$core->addBehavior('kutrlService',create_function(null,'return array("local","localKutrlService");')); +$__autoload['shorttoKutrlService'] = dirname(__FILE__).'/inc/services/class.shortto.service.php'; +$core->addBehavior('kutrlService',create_function(null,'return array("shortto","shorttoKutrlService");')); +$__autoload['trimKutrlService'] = dirname(__FILE__).'/inc/services/class.trim.service.php'; +$core->addBehavior('kutrlService',create_function(null,'return array("trim","trimKutrlService");')); +$__autoload['yourlsKutrlService'] = dirname(__FILE__).'/inc/services/class.yourls.service.php'; +$core->addBehavior('kutrlService',create_function(null,'return array("yourls","yourlsKutrlService");')); +$__autoload['suprKutrlService'] = dirname(__FILE__).'/inc/services/class.supr.service.php'; +$core->addBehavior('kutrlService',create_function(null,'return array("supr","suprKutrlService");')); + +# Shorten url passed through wiki functions +$__autoload['kutrlWiki'] = dirname(__FILE__).'/inc/lib.wiki.kutrl.php'; +$core->addBehavior('coreInitWikiPost',array('kutrlWiki','coreInitWiki')); +$core->addBehavior('coreInitWikiComment',array('kutrlWiki','coreInitWiki')); +$core->addBehavior('coreInitWikiSimpleComment',array('kutrlWiki','coreInitWiki')); + +# Public page +$core->url->register('kutrl','go','^go(/(.*?)|)$',array('urlKutrl','redirectUrl')); + +# Add kUtRL events on plugin activityReport +if (defined('ACTIVITY_REPORT')) +{ + require_once dirname(__FILE__).'/inc/lib.kutrl.activityreport.php'; +} +?> \ No newline at end of file diff --git a/_public.php b/_public.php new file mode 100644 index 0000000..37ca675 --- /dev/null +++ b/_public.php @@ -0,0 +1,625 @@ +tpl->setPath($core->tpl->getPath(),dirname(__FILE__).'/default-templates'); + +$core->addBehavior('publicBeforeDocument',array('pubKutrl','publicBeforeDocument')); +$core->addBehavior('publicHeadContent',array('pubKutrl','publicHeadContent')); +$core->addBehavior('publicBeforeContentFilter',array('pubKutrl','publicBeforeContentFilter')); +$core->addBehavior('templateBeforeValue',array('pubKutrl','templateBeforeValue')); +$core->addBehavior('templateAfterValue',array('pubKutrl','templateAfterValue')); + +$core->tpl->addBlock('kutrlPageIf',array('tplKutrl','pageIf')); +$core->tpl->addBlock('kutrlMsgIf',array('tplKutrl','pageMsgIf')); + +$core->tpl->addValue('kutrlPageURL',array('tplKutrl','pageURL')); +$core->tpl->addValue('kutrlMsg',array('tplKutrl','pageMsg')); +$core->tpl->addValue('kutrlHumanField',array('tplKutrl','humanField')); +$core->tpl->addValue('kutrlHumanFieldProtect',array('tplKutrl','humanFieldProtect')); + +$core->tpl->addBlock('AttachmentKutrlIf',array('tplKutrl','AttachmentKutrlIf')); +$core->tpl->addValue('AttachmentKutrl',array('tplKutrl','AttachmentKutrl')); +$core->tpl->addBlock('MediaKutrlIf',array('tplKutrl','MediaKutrlIf')); +$core->tpl->addValue('MediaKutrl',array('tplKutrl','MediaKutrl')); +$core->tpl->addBlock('EntryAuthorKutrlIf',array('tplKutrl','EntryAuthorKutrlIf')); +$core->tpl->addValue('EntryAuthorKutrl',array('tplKutrl','EntryAuthorKutrl')); +$core->tpl->addBlock('EntryKutrlIf',array('tplKutrl','EntryKutrlIf')); +$core->tpl->addValue('EntryKutrl',array('tplKutrl','EntryKutrl')); +$core->tpl->addBlock('CommentAuthorKutrlIf',array('tplKutrl','CommentAuthorKutrlIf')); +$core->tpl->addValue('CommentAuthorKutrl',array('tplKutrl','CommentAuthorKutrl')); +$core->tpl->addBlock('CommentPostKutrlIf',array('tplKutrl','CommentPostKutrlIf')); +$core->tpl->addValue('CommentPostKutrl',array('tplKutrl','CommentPostKutrl')); + +class urlKutrl extends dcUrlHandlers +{ + # Redirect !!! local !!! service only + public static function redirectUrl($args) + { + global $core, $_ctx; + $s = $core->blog->settings->kUtRL; + + # Not active, go to default 404 + if (!$s->kutrl_active) + { + self::p404(); + return; + } + # Not a valid url, go to kutrl 404 + if (!preg_match('#^(|(/(.*?)))$#',$args,$m)) + { + self::kutrl404(); + return; + } + + $args = isset($m[3]) ? $m[3] : ''; + $_ctx->kutrl_msg = ''; + $_ctx->kutrl_hmf = hmfKutrl::create(); + $_ctx->kutrl_hmfp = hmfKutrl::protect($_ctx->kutrl_hmf); + + $kut = new localKutrlService($core); + + # Nothing on url + if ($m[1] == '/') + { + $_ctx->kutrl_msg = 'No link given.'; + } + # find suffix on redirect url + $suffix = ''; + if (preg_match('@^([^?/#]+)(.*?)$@',$args,$more)) + { + $args = $more[1]; + $suffix = $more[2]; + } + # No arg, go to kurtl page + if ($args == '') + { + self::pageKutrl($kut); + return; + } + # Not find, go to kutrl 404 + if (false === ($url = $kut->getUrl($args))) + { + //$_ctx->kutrl_msg = 'Failed to find short link.'; + //self::pageKutrl($kut); + + self::kutrl404(); + return; + } + # Removed (empty url), go to kutrl 404 + if (!$url) + { + self::kutrl404(); + return; + } + + $core->blog->triggerBlog(); + http::redirect($url.$suffix); + return; + } + + private static function pageKutrl($kut) + { + global $core, $_ctx; + $s = $core->blog->settings->kUtRL; + + # Not active, go to default 404 + if (!$s->kutrl_active) + { + self::p404(); + return; + } + # Public page not active, go to kutrl 404 + if (!$s->kutrl_srv_local_public) + { + self::kutrl404(); + return; + } + # Validation form + $url = !empty($_POST['longurl']) ? trim($core->con->escape($_POST['longurl'])) : ''; + if (!empty($url)) + { + $hmf = !empty($_POST['hmf']) ? $_POST['hmf'] : '!'; + $hmfu = !empty($_POST['hmfp']) ? hmfKutrl::unprotect($_POST['hmfp']) : '?'; + + $err = false; + if (!$err) + { + if ($hmf != $hmfu) + { + $err = true; + $_ctx->kutrl_msg = __('Failed to verify protected field.'); + } + } + if (!$err) + { + if (!$kut->testService()) + { + $err = true; + $_ctx->kutrl_msg = __('Service is not well configured.'); + } + } + if (!$err) + { + if (!$kut->isValidUrl($url)) + { + $err = true; + $_ctx->kutrl_msg = __('This string is not a valid URL.'); + } + } + if (!$err) + { + if (!$kut->isLongerUrl($url)) + { + $err = true; + $_ctx->kutrl_msg = __('This link is too short.'); + } + } + if (!$err) + { + if (!$kut->isProtocolUrl($url)) + { + $err = true; + $_ctx->kutrl_msg = __('This type of link is not allowed.'); + } + } + + if (!$err) + { + if (!$kut->allow_external_url && !$kut->isBlogUrl($url)) + { + $err = true; + $_ctx->kutrl_msg = __('Short links are limited to this blog URL.'); + } + } + if (!$err) + { + if ($kut->isServiceUrl($url)) + { + $err = true; + $_ctx->kutrl_msg = __('This link is already a short link.'); + } + } + if (!$err) + { + if (false !== ($rs = $kut->isKnowUrl($url))) + { + $err = true; + + $url = $rs->url; + $new_url = $kut->url_base.$rs->hash; + + $_ctx->kutrl_msg = sprintf( + __('Short link for %s is %s'), + html::escapeHTML($url), + ''.$new_url.'' + ); + } + } + if (!$err) + { + if (false === ($rs = $kut->hash($url))) + { + $err = true; + $_ctx->kutrl_msg = __('Failed to create short link.'); + } + else + { + $url = $rs->url; + $new_url = $kut->url_base.$rs->hash; + + $_ctx->kutrl_msg = sprintf( + __('Short link for %s is %s'), + html::escapeHTML($url), + ''.$new_url.'' + ); + $core->blog->triggerBlog(); + + # ex: Send new url to messengers + if (!empty($rs)) + { + $core->callBehavior('publicAfterKutrlCreate',$core,$rs,__('New public short URL')); + } + } + } + } + + $core->tpl->setPath($core->tpl->getPath(),dirname(__FILE__).'/default-templates'); + self::serveDocument('kutrl.html'); + return; + } + + protected static function kutrl404() + { + global $core; + + if (!$core->blog->settings->kUtRL->kutrl_srv_local_404_active) + { + self::p404(); + return; + } + + $core->tpl->setPath($core->tpl->getPath(),dirname(__FILE__).'/default-templates'); + $_ctx =& $GLOBALS['_ctx']; + $core = $GLOBALS['core']; + + header('Content-Type: text/html; charset=UTF-8'); + http::head(404,'Not Found'); + $core->url->type = '404'; + $_ctx->current_tpl = 'kutrl404.html'; + $_ctx->content_type = 'text/html'; + + echo $core->tpl->getData($_ctx->current_tpl); + + # --BEHAVIOR-- publicAfterDocument + $core->callBehavior('publicAfterDocument',$core); + exit; + } +} + +class pubKutrl +{ + # List of template tag which content URL that can be shortenn + public static $know_tags = array( + 'AttachmentURL', + 'CategoryURL', + 'MediaURL', + 'EntryAuthorURL', + 'EntryURL', + 'EntryCategoryURL', + 'CommentAuthorURL', + 'CommentPostURL' + ); + + # Disable URL shoretning on filtered tag + public static function templateBeforeValue($core,$tag,$attr) + { + if (!empty($attr['disable_kutrl']) && in_array($tag,pubKutrl::$know_tags)) + { + return ''; + } + return; + } + + # Re unable it after tag + public static function templateAfterValue($core,$tag,$attr) + { + if (!empty($attr['disable_kutrl']) && in_array($tag,pubKutrl::$know_tags)) + { + return ''; + } + return; + } + + # Replace long urls on the fly (on filter) for default tags + public static function publicBeforeContentFilter($core,$tag,$args) + { + # Unknow tag + if (!in_array($tag,pubKutrl::$know_tags)) return; + + # URL shortening is disabled by tag attribute + if (empty($GLOBALS['disable_kutrl'])) + { + # kUtRL is not activated + if (!$core->blog->settings->kUtRL->kutrl_active + || !$core->blog->settings->kUtRL->kutrl_tpl_active) return; + + global $_ctx; + + # Oups + if (!$_ctx->exists('kutrl')) return; + + # Existing + if (false !== ($kutrl_rs = $_ctx->kutrl->isKnowUrl($args[0]))) + { + $args[0] = $_ctx->kutrl->url_base.$kutrl_rs->hash; + } + # New + elseif (false !== ($kutrl_rs = $_ctx->kutrl->hash($args[0]))) + { + $args[0] = $_ctx->kutrl->url_base.$kutrl_rs->hash; + + # ex: Send new url to messengers + if (!empty($kutrl_rs)) + { + $core->callBehavior('publicAfterKutrlCreate',$core,$kutrl_rs,__('New public short URL')); + } + } + } + } + + public static function publicBeforeDocument($core) + { + global $_ctx; + $s = $core->blog->settings->kUtRL; + + # Passive : all kutrl tag return long url + $_ctx->kutrl_passive = (boolean) $s->kutrl_tpl_passive; + + if (!$s->kutrl_active || !$s->kutrl_tpl_service) return; + + if (null === ($kut = kutrl::quickPlace('tpl'))) return; + + $_ctx->kutrl = $kut; + } + + public static function publicHeadContent($core) + { + $css = $core->blog->settings->kUtRL->kutrl_srv_local_css; + if ($css) + { + echo + "\n \n". + "\n"; + } + } +} + +class tplKutrl +{ + public static function pageURL($attr) + { + $f = $GLOBALS['core']->tpl->getFilters($attr); + return 'blog->url.$core->url->getBase("kutrl")').'; ?>'; + } + + public static function pageIf($attr,$content) + { + $operator = isset($attr['operator']) ? self::getOperator($attr['operator']) : '&&'; + + if (isset($attr['is_active'])) + { + $sign = (boolean) $attr['is_active'] ? '' : '!'; + $if[] = $sign.'$core->blog->settings->kUtRL->kutrl_srv_local_public'; + } + + if (empty($if)) + { + return $content; + } + + return + "\n". + $content. + "\n"; + } + + public static function pageMsgIf($attr,$content) + { + $operator = isset($attr['operator']) ? self::getOperator($attr['operator']) : '&&'; + + if (isset($attr['has_message'])) + { + $sign = (boolean) $attr['has_message'] ? '!' : '='; + $if[] = '"" '.$sign.'= $_ctx->kutrl_msg'; + } + + if (empty($if)) + { + return $content; + } + + return + "\n". + $content. + "\n"; + } + + public static function pageMsg($attr) + { + return 'kutrl_msg; ?>'; + } + + public static function humanField($attr) + { + return "kutrl_hmf); ?>"; + } + + public static function humanFieldProtect($attr) + { + return + "kutrl_hmfp; ?>\" />". + "formNonce(); ?>"; + } + + public static function AttachmentKutrlIf($attr,$content) + { + return self::genericKutrlIf('$attach_f->file_url',$attr,$content); + } + + public static function AttachmentKutrl($attr) + { + return self::genericKutrl('$attach_f->file_url',$attr); + } + + public static function MediaKutrlIf($attr,$content) + { + return self::genericKutrlIf('$_ctx->file_url',$attr,$content); + } + + public static function MediaKutrl($attr) + { + return self::genericKutrl('$_ctx->file_url',$attr); + } + + public static function EntryAuthorKutrlIf($attr,$content) + { + return self::genericKutrlIf('$_ctx->posts->user_url',$attr,$content); + } + + public static function EntryAuthorKutrl($attr) + { + return self::genericKutrl('$_ctx->posts->user_url',$attr); + } + + public static function EntryKutrlIf($attr,$content) + { + return self::genericKutrlIf('$_ctx->posts->getURL()',$attr,$content); + } + + public static function EntryKutrl($attr) + { + return self::genericKutrl('$_ctx->posts->getURL()',$attr); + } + + public static function CommentAuthorKutrlIf($attr,$content) + { + return self::genericKutrlIf('$_ctx->comments->getAuthorURL()',$attr,$content); + } + + public static function CommentAuthorKutrl($attr) + { + return self::genericKutrl('$_ctx->comments->getAuthorURL()',$attr); + } + + public static function CommentPostKutrlIf($attr,$content) + { + return self::genericKutrlIf('$_ctx->comments->getPostURL()',$attr,$content); + } + + public static function CommentPostKutrl($attr) + { + return self::genericKutrl('$_ctx->comments->getPostURL()',$attr); + } + + protected static function genericKutrlIf($str,$attr,$content) + { + $operator = isset($attr['operator']) ? self::getOperator($attr['operator']) : '&&'; + + if (isset($attr['is_active'])) + { + $sign = (boolean) $attr['is_active'] ? '' : '!'; + $if[] = $sign.'$_ctx->exists("kutrl")'; + } + + if (isset($attr['passive_mode'])) + { + $sign = (boolean) $attr['passive_mode'] ? '' : '!'; + $if[] = $sign.'$_ctx->kutrl_passive'; + } + + if (isset($attr['has_kutrl'])) + { + $sign = (boolean) $attr['has_kutrl'] ? '!' : '='; + $if[] = '($_ctx->exists("kutrl") && false '.$sign.'== $_ctx->kutrl->select('.$str.',null,null,"kutrl"))'; + } + + if (empty($if)) + { + return $content; + } + return + "\n". + $content. + "\n"; + } + + protected static function genericKutrl($str,$attr) + { + $f = $GLOBALS['core']->tpl->getFilters($attr); + return + "preview) { \n". + " echo ".sprintf($f,$str)."; ". + "} else { \n". + # Disable + "if (!\$_ctx->exists('kutrl')) { \n". + # Passive mode + " if (\$_ctx->kutrl_passive) { ". + " echo ".sprintf($f,$str)."; ". + " } \n". + "} else { \n". + # Existing + " if (false !== (\$kutrl_rs = \$_ctx->kutrl->isKnowUrl(".$str."))) { ". + " echo ".sprintf($f,'$_ctx->kutrl->url_base.$kutrl_rs->hash')."; ". + " } \n". + # New + " elseif (false !== (\$kutrl_rs = \$_ctx->kutrl->hash(".$str."))) { ". + " echo ".sprintf($f,'$_ctx->kutrl->url_base.$kutrl_rs->hash')."; ". + + # ex: Send new url to messengers + " if (!empty(\$kutrl_rs)) { ". + " \$core->callBehavior('publicAfterKutrlCreate',\$core,\$kutrl_rs,__('New public short URL')); ". + " } \n". + + " } \n". + " unset(\$kutrl_rs); \n". + "} \n". + "} \n". + "?>\n"; + } + + protected static function getOperator($op) + { + switch (strtolower($op)) + { + case 'or': + case '||': + return '||'; + case 'and': + case '&&': + default: + return '&&'; + } + } +} + +class hmfKutrl +{ + public static $chars = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'; + + public static function create($len=6) + { + $res = ''; + $chars = self::$chars; + + for($i = 0;$i < $len; $i++) + { + $res .= $chars[rand(0,strlen($chars)-1)]; + } + + return $res; + } + + public static function protect($str) + { + $res = ''; + $chars = self::$chars; + + for($i = 0; $i < strlen($str);$i++) + { + $res .= $chars[rand(0,strlen($chars)-1)].$str[$i]; + } + + return $res; + } + + public static function unprotect($str) + { + $res = ''; + + for($i = 0; $i < strlen($str);$i++) + { + $i++; + $res .= $str[$i]; + } + + return $res; + } +} +?> \ No newline at end of file diff --git a/_uninstall.php b/_uninstall.php new file mode 100644 index 0000000..9e22e41 --- /dev/null +++ b/_uninstall.php @@ -0,0 +1,67 @@ +addUserAction( + /* type */ 'settings', + /* action */ 'delete_all', + /* ns */ 'kUtRL', + /* description */ __('delete all settings') +); + +$this->addUserAction( + /* type */ 'tables', + /* action */ 'delete', + /* ns */ 'kutrl', + /* description */ __('delete table') +); + +$this->addUserAction( + /* type */ 'plugins', + /* action */ 'delete', + /* ns */ 'kUtRL', + /* description */ __('delete plugin files') +); + +$this->addUserAction( + /* type */ 'versions', + /* action */ 'delete', + /* ns */ 'kUtRL', + /* description */ __('delete the version number') +); + + +# Delete only dc version and plugin files from pluginsBeforeDelete +# Keep table + +$this->addDirectAction( + /* type */ 'settings', + /* action */ 'delete_all', + /* ns */ 'kUtRL', + /* description */ sprintf(__('delete all %s settings'),'kUtRL') +); + +$this->addDirectAction( + /* type */ 'versions', + /* action */ 'delete', + /* ns */ 'kUtRL', + /* description */ sprintf(__('delete %s version number'),'kUtRL') +); + +$this->addDirectAction( + /* type */ 'plugins', + /* action */ 'delete', + /* ns */ 'kUtRL', + /* description */ sprintf(__('delete %s plugin files'),'kUtRL') +); +?> \ No newline at end of file diff --git a/_widgets.php b/_widgets.php new file mode 100644 index 0000000..31eb81f --- /dev/null +++ b/_widgets.php @@ -0,0 +1,211 @@ +addBehavior('initWidgets',array('widgetKutrl','adminShorten')); +$core->addBehavior('initWidgets',array('widgetKutrl','adminRank')); + +class widgetKutrl +{ + public static function adminShorten($w) + { + $w->create('shortenkutrl',__('Links shortener'), + array('widgetKutrl','publicShorten') + ); + $w->shortenkutrl->setting('title', + __('Title:'),__('Shorten link'),'text' + ); + $w->shortenkutrl->setting('homeonly', + __('Home page only'),1,'check' + ); + } + + public static function adminRank($w) + { + $w->create('rankkutrl',__('Top of short links'), + array('widgetKutrl','publicRank') + ); + $w->rankkutrl->setting('title', + __('Title:'),__('Top of short links'),'text' + ); + $w->rankkutrl->setting('text', + __('Text: (Use wildcard %rank%, %hash%, %url%, %count%, %counttext%)'),'%rank% - %url% - %counttext%','text' + ); + $w->rankkutrl->setting('urllen', + __('URL length (if truncate)'),20,'text' + ); + $w->rankkutrl->setting('type', + __('Type:'),'all','combo',array( + __('All') => '-', + __('Mini URL') => 'localnormal', + __('Custom URL') => 'localcustom', + __('Semi-custom') => 'localmix' + ) + ); + $w->rankkutrl->setting('mixprefix', + __('Semi-custom prefix: (only if you want limit to a particular prefix)'), + '','text' + ); + $w->rankkutrl->setting('sortby', + __('Sort by:'),'kut_counter','combo',array( + __('Date') => 'kut_dt', + __('Rank') => 'kut_counter', + __('Hash') => 'kut_hash' + ) + ); + $w->rankkutrl->setting('sort', + __('Sort:'),'desc','combo',array( + __('Ascending') => 'asc', + __('Descending') => 'desc' + ) + ); + $w->rankkutrl->setting('limit', + __('Limit:'),'10','text' + ); + $w->rankkutrl->setting('hideempty', + __('Hide no followed links'),0,'check' + ); + $w->rankkutrl->setting('homeonly', + __('Home page only'),1,'check' + ); + } + + public static function publicShorten($w) + { + global $core; + $s = $core->blog->settings->kUtRL; + + if (!$s->kutrl_active + || !$s->kutrl_srv_local_public + || $w->homeonly && $core->url->type != 'default' + || $core->url->type == 'kutrl') return; + + $hmf = hmfKutrl::create(); + $hmfp = hmfKutrl::protect($hmf); + + return + '
'. + ($w->title ? '

'.html::escapeHTML($w->title).'

' : ''). + '
'. + '

'. + '

'. + '

'. + form::hidden('hmfp',$hmfp). + $core->formNonce(). + '

'. + '
'. + '
'; + } + + public static function publicRank($w) + { + global $core; + $s = $core->blog->settings->kUtRL; + + if (!$s->kutrl_active + || $w->homeonly && $core->url->type != 'default') return; + + $type = in_array($w->type,array('localnormal','localmix','localcustom')) ? + "AND kut_type ='".$w->type."' " : + "AND kut_type ".$core->con->in(array('localnormal','localmix','localcustom'))." "; + + $hide = (boolean) $w->hideempty ? 'AND kut_counter > 0 ' : ''; + + $more = ''; + if ($w->type == 'localmix' && '' != $w->mixprefix) + { + $more = "AND kut_hash LIKE '".$core->con->escape($w->mixprefix)."%' "; + } + + $order = ($w->sortby && in_array($w->sortby,array('kut_dt','kut_counter','kut_hash'))) ? + $w->sortby.' ' : 'kut_dt '; + + $order .= $w->sort == 'desc' ? 'DESC' : 'ASC'; + + $limit = $core->con->limit(abs((integer) $w->limit)); + + $rs = $core->con->select( + 'SELECT kut_counter, kut_hash '. + "FROM ".$core->prefix."kutrl ". + "WHERE blog_id='".$core->con->escape($core->blog->id)."' ". + "AND kut_service = 'local' ". + $type.$hide.$more.'ORDER BY '.$order.$limit + ); + + if ($rs->isEmpty()) return; + + $content = ''; + $i = 0; + + while($rs->fetch()) + { + $i++; + $rank = ''.$i.''; + + $hash = $rs->kut_hash; + $url = $core->blog->url.$core->url->getBase('kutrl').'/'.$hash; + $cut_len = - abs((integer) $w->urllen); + + if (strlen($url) > $cut_len) + { + $url = '...'.substr($url,$cut_len); + } +/* + if (strlen($hash) > $cut_len) + { + $url = '...'.substr($hash,$cut_len); + } +//*/ + if ($rs->kut_counter == 0) + { + $counttext = __('never followed'); + } + elseif ($rs->kut_counter == 1) + { + $counttext = __('followed one time'); + } + else + { + $counttext = sprintf(__('followed %s times'),$rs->kut_counter); + } + + $content .= + '
  • '. + str_replace( + array('%rank%','%hash%','%url%','%count%','%counttext%'), + array($rank,$hash,$url,$rs->kut_counter,$counttext), + $w->text + ). + '
  • '; + + } + + if (!$content) return; + + return + '
    '. + ($w->title ? '

    '.html::escapeHTML($w->title).'

    ' : ''). + '
      '.$content.'
    '. + '
    '; + } +} +?> \ No newline at end of file diff --git a/default-templates/img/broken-link.png b/default-templates/img/broken-link.png new file mode 100644 index 0000000..8fb6046 Binary files /dev/null and b/default-templates/img/broken-link.png differ diff --git a/default-templates/kutrl.html b/default-templates/kutrl.html new file mode 100644 index 0000000..0827236 --- /dev/null +++ b/default-templates/kutrl.html @@ -0,0 +1,87 @@ + + + + + + + + {{tpl:BlogName encode_html="1"}}<tpl:PaginationIf start="0"> - {{tpl:lang page}} {{tpl:PaginationCurrent}}</tpl:PaginationIf> + + + + + + + - {{tpl:lang page}} {{tpl:PaginationCurrent}}" /> + + + + + + + + + + + + + + + + + + {{tpl:include src="_head.html"}} + + + +
    + +{{tpl:include src="_top.html"}} + +
    + +
    +
    + +
    +

    {{tpl:lang Links shortener}}

    + +

    {{tpl:kutrlMsg}}

    +
    + + +
    +

    +

    +

    + + {{tpl:kutrlHumanFieldProtect}} +

    +
    +
    +
    + +
    +
    + + + +
    + +{{tpl:include src="_footer.html"}} +
    + + \ No newline at end of file diff --git a/default-templates/kutrl404.html b/default-templates/kutrl404.html new file mode 100644 index 0000000..74adc9c --- /dev/null +++ b/default-templates/kutrl404.html @@ -0,0 +1,67 @@ + + + + + + + + {{tpl:lang Document not found}} - {{tpl:BlogName encode_html="1"}} + + + + + + + + + + + + + + + + {{tpl:include src="_head.html"}} + + + +
    +{{tpl:include src="_top.html"}} + +
    + +
    +
    + +
    +

    {{tpl:lang URL not found}}

    +
    + +
    +

    {{tpl:lang The URL you are looking for does not exist.}}

    +

    broken link

    + +

    {{tpl:lang Create your own short URL}}

    +
    +
    + +
    +
    + + + +
    + +{{tpl:include src="_footer.html"}} +
    + + \ No newline at end of file diff --git a/icon-b.png b/icon-b.png new file mode 100644 index 0000000..0359bb8 Binary files /dev/null and b/icon-b.png differ diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..d995261 Binary files /dev/null and b/icon.png differ diff --git a/inc/class.kutrl.php b/inc/class.kutrl.php new file mode 100644 index 0000000..cfbade9 --- /dev/null +++ b/inc/class.kutrl.php @@ -0,0 +1,104 @@ +getBehaviors('kutrlService'); + + if (empty($list)) return array(); + + $service = array(); + foreach($list as $k => $callback) + { + try + { + list($service_id,$service_class) = call_user_func($callback); + $services[(string) $service_id] = (string) $service_class; + } + catch (Exception $e) {} + } + return $services; + } + + # Silently try to load a service according to its id + # Return null on error else service on success + public static function quickService($id='') + { + global $core; + + try + { + if (empty($id)) { + return null; + } + $services = self::getServices($core); + if (isset($services[$id])) { + return new $services[$id]($core); + } + } + catch(Exception $e) { } + + return null; + } + + # Silently try to load a service according to its place + # Return null on error else service on success + public static function quickPlace($place='plugin') + { + global $core; + + try + { + if (!in_array($place,array('tpl','wiki','admin','plugin'))) { + return null; + } + $id = $core->blog->settings->kUtRL->get('kutrl_'.$place.'_service'); + if (!empty($id)) { + return self::quickService($id); + } + } + catch(Exception $e) { } + + return null; + } + + # Silently try to reduce url (using 'plugin' place) + # return long url on error else short url on success + public static function quickReduce($url,$custom=null,$place='plugin') + { + global $core; + + try + { + $srv = self::quickPlace($place); + if (empty($srv)) { + return $url; + } + $rs = $srv->hash($url,$custom); + if (empty($rs)) { + return $url; + } + + return $srv->url_base.$rs->hash; + } + catch(Exception $e) { } + + return $url; + } +} +?> \ No newline at end of file diff --git a/inc/img/kutrl_logo.png b/inc/img/kutrl_logo.png new file mode 100644 index 0000000..def9fa8 Binary files /dev/null and b/inc/img/kutrl_logo.png differ diff --git a/inc/index.link.php b/inc/index.link.php new file mode 100644 index 0000000..d2bd1a1 --- /dev/null +++ b/inc/index.link.php @@ -0,0 +1,153 @@ +con->escape($_POST['str'])); + $hash = empty($_POST['custom']) ? null : $_POST['custom']; + + if (empty($url)) + throw new Exception(__('There is nothing to shorten.')); + + if (!$kut->testService()) + throw new Exception(__('Service is not well configured.')); + + if (null !== $hash && !$kut->allow_custom_hash) + throw new Exception(__('This service does not allowed custom hash.')); + + if (!$kut->isValidUrl($url)) + throw new Exception(__('This link is not a valid URL.')); + + if (!$kut->isLongerUrl($url)) + throw new Exception(__('This link is too short.')); + + if (!$kut->isProtocolUrl($url)) + throw new Exception(__('This type of link is not allowed.')); + + if (!$kut->allow_external_url && !$kut->isBlogUrl($url)) + throw new Exception(__('Short links are limited to this blog URL.')); + + if ($kut->isServiceUrl($url)) + throw new Exception(__('This link is already a short link.')); + + if (null !== $hash && false !== ($rs = $kut->isKnowHash($hash))) + throw new Exception(__('This custom short url is already taken.')); + + if (false !== ($rs = $kut->isKnowUrl($url))) + { + $url = $rs->url; + $new_url = $kut->url_base.$rs->hash; + $msg = + '

    '. + sprintf(__('Short link for %s is %s'), + ''.html::escapeHTML($url).'', + ''.$new_url.'' + ).'

    '; + } + else + { + if (false === ($rs = $kut->hash($url,$hash))) + { + if ($kut->error->flag()) + { + throw new Exception($kut->error->toHTML()); + } + throw new Exception(__('Failed to create short link. This could be caused by a service failure.')); + } + else + { + $url = $rs->url; + $new_url = $kut->url_base.$rs->hash; + $msg = + '

    '. + sprintf(__('Short link for %s is %s'), + ''.html::escapeHTML($url).'', + ''.$new_url.'' + ).'

    '; + + # ex: Send new url to messengers + if (!empty($rs)) + { + $core->callBehavior('adminAfterKutrlCreate',$core,$rs,__('New short URL')); + } + } + } + } + catch (Exception $e) + { + $core->error->add($e->getMessage()); + } +} + +echo ' + +kUtRL, '.__('Links shortener').''.$header.' + +

    kUtRL'. +' › '.__('Links').''. +' › '.__('New link'). +'

    '.$msg; + +if (null === $kut) +{ + echo '

    '.__('You must set an admin service.').'

    '; +} +else +{ + echo ' + '; +} +dcPage::helpBlock('kUtRL'); +echo $footer.''; +?> \ No newline at end of file diff --git a/inc/index.links.php b/inc/index.links.php new file mode 100644 index 0000000..8a87b0d --- /dev/null +++ b/inc/index.links.php @@ -0,0 +1,267 @@ +rs->isEmpty()) + echo '

    '.__('No short link').'

    '; + + else { + $pager = new pager($page,$this->rs_count,$nb_per_page,10); + + $pager->base_url = $url; + + $html_block = + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + '%s'. + '
    '.__('Hash').''.__('Link').''.__('Date').''.__('Service').'
    '; + + echo '

    '.__('Page(s)').' : '.$pager->getLinks().'

    '; + $blocks = explode('%s',$html_block); + echo $blocks[0]; + + $this->rs->index(((integer)$page - 1) * $nb_per_page); + $iter = 0; + while ($iter < $nb_per_page) { + + echo $this->line($url,$iter); + + if ($this->rs->isEnd()) + break; + else + $this->rs->moveNext(); + + $iter++; + } + echo $blocks[1]; + echo '

    '.__('Page(s)').' : '.$pager->getLinks().'

    '; + } + } + + private function line($url,$loop) + { + $type = $this->rs->kut_type; + $hash = $this->rs->kut_hash; + + if (null !== ($o = kutrl::quickService($this->rs->kut_type))) + { + $type = ''.$o->name.''; + $hash = ''.$hash.''; + } + + return + ''."\n". + ''. + form::checkbox(array('entries['.$loop.']'),$this->rs->kut_id,0). + ''. + ''. + $hash. + "\n". + ''. + ''.$this->rs->kut_url.''. + "\n". + ''. + dt::dt2str(__('%Y-%m-%d %H:%M'),$this->rs->kut_dt,$this->core->auth->getInfo('user_tz')). + "\n". + ''. + $type. + "\n". + ''."\n"; + } +} + +# Logs class +$log = new kutrlLog($core); + +# Filters +$show_filters = false; +$urlsrv = !empty($_GET['urlsrv']) ? $_GET['urlsrv'] : ''; +$sortby = !empty($_GET['sortby']) ? $_GET['sortby'] : 'kut_dt'; +$order = !empty($_GET['order']) ? $_GET['order'] : 'desc'; + +$page = !empty($_GET['page']) ? (integer) $_GET['page'] : 1; +$nb_per_page = 30; +if (!empty($_GET['nb']) && (integer) $_GET['nb'] > 0) { + if ($nb_per_page != $_GET['nb']) $show_filters = true; + $nb_per_page = (integer) $_GET['nb']; +} + +# Combos +$sortby_combo = array( + __('Date') => 'kut_dt', + __('Long link') => 'kut_url', + __('Short link') => 'kut_hash' +); + +$order_combo = array( + __('Descending') => 'desc', + __('Ascending') => 'asc' +); + +$services_combo = array(); +foreach(kutrl::getServices($core) as $service_id => $service) +{ + $o = new $service($core); + $services_combo[__($o->name)] = $o->id; +} +$ext_services_combo = array_merge(array(__('Disabled')=>''),$services_combo); +$lst_services_combo = array_merge(array('-'=>''),$services_combo); + +# Params for list +$params = array(); +$params['limit'] = array((($page-1)*$nb_per_page),$nb_per_page); + +if ($sortby != '' && in_array($sortby,$sortby_combo)) +{ + if ($urlsrv != '' && in_array($urlsrv,$lst_services_combo)) + $params['kut_type'] = $urlsrv; + + if ($order != '' && in_array($order,$order_combo)) + $params['order'] = $sortby.' '.$order; + + if ($sortby != 'kut_dt' || $order != 'desc' || $urlsrv != '') + $show_filters = true; +} + +$pager_base_url = + $p_url. + '&tab=list'. + '&urlsrv='.$urlsrv. + '&sortby='.$sortby. + '&order='.$order. + '&nb='.$nb_per_page. + '&page=%s'; + + +# Delete links from list +if ($action == 'deletelinks') +{ + try + { + foreach($_POST['entries'] as $k => $id) + { + $rs = $log->getLogs(array('kut_id'=>$id)); + if ($rs->isEmpty()) continue; + + if (null === ($o = kutrl::quickService($rs->kut_type))) continue; + $o->remove($rs->kut_url); + } + + $core->blog->triggerBlog(); + http::redirect($p_url.'&part=links&urlsrv='.$urlsrv.'&sortby='.$sortby.'&order='.$order.'&nb='.$nb_per_page.'&page='.$page.'&msg='.$action); + } + catch (Exception $e) { + $core->error->add($e->getMessage()); + } +} + +# Get links and pager +try +{ + $list_all = $log->getLogs($params); + $list_counter = $log->getLogs($params,true)->f(0); + $list_current = new kutrlLinksList($core,$list_all,$list_counter,$pager_base_url); +} +catch (Exception $e) +{ + $core->error->add($e->getMessage()); +} + +if (!$show_filters) { + $header .= dcPage::jsLoad('js/filter-controls.js'); +} + +echo ' + +kUtRL, '.__('Links shortener').''. +"\n\n". +$header.' + +

    kUtRL'. +' › '.__('Links'). +' - '.__('New link').''. +'

    '.$msg; + +if (!$show_filters) { + echo '

    '. + __('Filters').'

    '; +} + +echo ' +
    +
    '.__('Filters').' +
    +
    + +
    +
    + + +
    +
    +

    + +'. +form::hidden(array('p'),'kUtRL'). +form::hidden(array('part'),'links').' +

    +
    +
    +
    +
    +
    +
    '; + +$list_current->display($page,$nb_per_page,$pager_base_url); + +echo ' +
    +

    +

    +'. +form::hidden(array('action'),'deletelinks'). +form::hidden(array('urlsrv'),$urlsrv). +form::hidden(array('sortby'),$sortby). +form::hidden(array('order'),$order). +form::hidden(array('page'),$page). +form::hidden(array('nb'),$nb_per_page). +form::hidden(array('p'),'kUtRL'). +form::hidden(array('part'),'links'). +$core->formNonce().' +

    +
    +
    '; + +dcPage::helpBlock('kUtRL'); +echo $footer.''; +?> \ No newline at end of file diff --git a/inc/index.service.php b/inc/index.service.php new file mode 100644 index 0000000..9fb236a --- /dev/null +++ b/inc/index.service.php @@ -0,0 +1,92 @@ + $service) + { + $o = new $service($core); + $o->saveSettings(); + } + $core->blog->triggerBlog(); + http::redirect($p_url.'&part=service§ion='.$section.'&msg='.$action); + } + catch (Exception $e) + { + $core->error->add($e->getMessage()); + } +} + +echo ' + +kUtRL, '.__('Links shortener').''.$header. +dcPage::jsLoad('index.php?pf=kUtRL/js/service.js'). +"\n". +' + +

    kUtRL'. +' › '.__('Links').''. +' › '.__('Services'). +' - '.__('New link').''. +'

    '.$msg.' +
    '; + +foreach(kutrl::getServices($core) as $service_id => $service) +{ + $o = new $service($core); + + echo '
    '.$o->name.''; + + if (!empty($msg)) + { + echo '

    '.( + $o->testService() ? + $img_green.' '.sprintf(__('%s API is well configured and runing.'),$o->name) : + $img_red.' '.sprintf(__('Failed to test %s API.'),$o->name) + ).'

    '; + //if ($o->error->flag()) { + echo $o->error->toHTML(); + //} + } + + if (!empty($o->home)) + { + echo '

    '.sprintf(__('Learn more about %s.'),$o->name).'

    '; + } + + $o->settingsForm(); + + echo '
    '; +} + +echo ' +
    +

    '. +$core->formNonce(). +form::hidden(array('p'),'kUtRL'). +form::hidden(array('part'),'service'). +form::hidden(array('action'),'saveservice'). +form::hidden(array('section'),$section).' +

    +
    '; +dcPage::helpBlock('kUtRL'); +echo $footer.''; +?> \ No newline at end of file diff --git a/inc/index.setting.php b/inc/index.setting.php new file mode 100644 index 0000000..11ca5d0 --- /dev/null +++ b/inc/index.setting.php @@ -0,0 +1,164 @@ +kutrl_active; +$s_plugin_service = (string) $s->kutrl_plugin_service; +$s_admin_service = (string) $s->kutrl_admin_service; +$s_tpl_service = (string) $s->kutrl_tpl_service; +$s_wiki_service = (string) $s->kutrl_wiki_service; +$s_allow_external_url = (boolean) $s->kutrl_allow_external_url; +$s_tpl_passive = (boolean) $s->kutrl_tpl_passive; +$s_tpl_active = (boolean) $s->kutrl_tpl_active; +$s_admin_entry_default = (string) $s->kutrl_admin_entry_default; + +if ($default_part == 'setting' && $action == 'savesetting') +{ + try { + $s_active = !empty($_POST['s_active']); + $s_admin_service = $_POST['s_admin_service']; + $s_plugin_service = $_POST['s_plugin_service']; + $s_tpl_service = $_POST['s_tpl_service']; + $s_wiki_service = $_POST['s_wiki_service']; + $s_allow_external_url = !empty($_POST['s_allow_external_url']); + $s_tpl_passive = !empty($_POST['s_tpl_passive']); + $s_tpl_active = !empty($_POST['s_tpl_active']); + $s_admin_entry_default = !empty($_POST['s_admin_entry_default']); + + $s->put('kutrl_active',$s_active); + $s->put('kutrl_plugin_service',$s_plugin_service); + $s->put('kutrl_admin_service',$s_admin_service); + $s->put('kutrl_tpl_service',$s_tpl_service); + $s->put('kutrl_wiki_service',$s_wiki_service); + $s->put('kutrl_allow_external_url',$s_allow_external_url); + $s->put('kutrl_tpl_passive',$s_tpl_passive); + $s->put('kutrl_tpl_active',$s_tpl_active); + $s->put('kutrl_admin_entry_default',$s_admin_entry_default); + + $core->blog->triggerBlog(); + + http::redirect($p_url.'&part=setting&msg='.$action.'§ion='.$section); + } + catch (Exception $e) { + $core->error->add($e->getMessage()); + } +} + +$services_combo = array(); +foreach(kutrl::getServices($core) as $service_id => $service) +{ + $o = new $service($core); + $services_combo[__($o->name)] = $o->id; +} +$ext_services_combo = array_merge(array(__('Disabled')=>''),$services_combo); +$lst_services_combo = array_merge(array('-'=>''),$services_combo); + +echo ' + +kUtRL, '.__('Links shortener').''.$header. +dcPage::jsLoad('index.php?pf=kUtRL/js/setting.js'). +"\n". +' + +

    kUtRL'. +' › '.__('Links').''. +' › '.__('Settings'). +' - '.__('New link').''. +'

    '.$msg.' +
    + +
    '. __('Plugin activation').' +

    +
    + +
    '. __('General rules').' +

    +

    '.__('Not only link started with this blog URL could be shortened.').'

    +

    +

    '.__('If this extension is disabled and the passive mode is enabled, "kutrl" tags (like EntryKurl) will display long urls instead of nothing on templates.').'

    +

    +

    '.__('If the active mode is enabled, all know default template tags (like EntryURL) will display short urls instead of long ones on templates.').'
    '. +__('You can disable URL shortening for a specific template tag by adding attribute disable_kutrl="1" to it.').'

    +

    +

    '.__('This can be changed on page of creation/edition of an entry.').'

    +
    + +
    '. __('Default services').' +

    +

    '.__('Service to use in this admin page and on edit page of an entry.').'

    +

    +

    '.__('Service to use on third part plugins.').'

    +

    +

    '.__('Shorten links automatically when using template value like "EntryKutrl".').'

    +

    +

    '.__('Shorten links automatically found in contents using wiki synthax.').'

    +
    + +
    +

    '. +$core->formNonce(). +form::hidden(array('p'),'kUtRL'). +form::hidden(array('part'),'setting'). +form::hidden(array('action'),'savesetting'). +form::hidden(array('section'),$section).' +

    +
    '; +dcPage::helpBlock('kUtRL'); +echo $footer.''; +?> \ No newline at end of file diff --git a/inc/lib.kutrl.activityreport.php b/inc/lib.kutrl.activityreport.php new file mode 100644 index 0000000..a1c279d --- /dev/null +++ b/inc/lib.kutrl.activityreport.php @@ -0,0 +1,38 @@ +activityReport->addGroup('kutrl',__('Plugin kUtRL')); + +# from BEHAVIOR kutrlAfterCreateShortUrl in kUtRL/inc/lib.kutrl.srv.php +$core->activityReport->addAction( + 'kutrl', + 'create', + __('Short link creation'), + __('New short link of type "%s" and hash "%s" was created.'), + 'kutrlAfterCreateShortUrl', + array('kutrlActivityReportBehaviors','kutrlCreate') +); + +class kutrlActivityReportBehaviors +{ + public static function kutrlCreate($rs) + { + $logs = array($rs->type,$rs->hash); + + $GLOBALS['core']->activityReport->addLog('kutrl','create',$logs); + } +} +?> \ No newline at end of file diff --git a/inc/lib.kutrl.log.php b/inc/lib.kutrl.log.php new file mode 100644 index 0000000..974eede --- /dev/null +++ b/inc/lib.kutrl.log.php @@ -0,0 +1,314 @@ +core = $core; + $this->table = $core->prefix.'kutrl'; + $this->blog = $core->con->escape($core->blog->id); + $this->con = $core->con; + } + + public function nextId() + { + return $this->con->select( + 'SELECT MAX(kut_id) FROM '.$this->table + )->f(0) + 1; + } + + public function insert($url,$hash,$type,$service='kutrl') + { + $cur = $this->con->openCursor($this->table); + $this->con->writeLock($this->table); + + try { + $cur->kut_id = $this->nextId(); + $cur->blog_id = $this->blog; + $cur->kut_url = (string) $url; + $cur->kut_hash = (string) $hash; + $cur->kut_type = (string) $type; + $cur->kut_service = (string) $service; + $cur->kut_dt = date('Y-m-d H:i:s'); + $cur->kut_counter = 0; + + $cur->insert(); + $this->con->unlock(); + + return array( + 'id' => $cur->kut_id, + 'url' => $url, + 'hash' => $hash, + 'type' => $type, + 'service' => $service, + 'counter '=> 0 + ); + } + catch (Exception $e) + { + $this->con->unlock(); + throw $e; + } + return false; + } + + public function select($url=null,$hash=null,$type=null,$service='kutrl') + { + //$this->con->writeLock($this->table); + + $req = + 'SELECT kut_id as id, kut_hash as hash, kut_url as url, '. + 'kut_type as type, kut_service as service, kut_counter as counter '. + 'FROM '.$this->table.' '. + "WHERE blog_id = '".$this->blog."' ". + "AND kut_service = '".$this->con->escape($service)."' "; + + if (null !== $url) + $req .= "AND kut_url = '".$this->con->escape($url)."' "; + + if (null !== $hash) + $req .= "AND kut_hash = '".$this->con->escape($hash)."' "; + + if (null !== $type) { + if (is_array($type)) { + $req .= "AND kut_type '".$this->con->in($type)."' "; + } + else { + $req .= "AND kut_type = '".$this->con->escape($type)."' "; + } + } + + $req .= 'ORDER BY kut_dt DESC '.$this->con->limit(1); + + $rs = $this->con->select($req); + //$this->con->unlock(); + + return $rs->isEmpty() ? false : $rs; + } + + public function clear($id) + { + $id = (integer) $id; + + $cur = $this->con->openCursor($this->table); + $this->con->writeLock($this->table); + + try + { + $cur->kut_url = ''; + $cur->kut_dt = date('Y-m-d H:i:s'); + $cur->kut_counter = 0; + + $cur->update( + "WHERE blog_id='".$this->blog."' ". + "AND kut_id='".$id."' " + ); + $this->con->unlock(); + + return true; + } + catch (Exception $e) + { + $this->con->unlock(); + throw $e; + } + return false; + } + + public function delete($id) + { + $id = (integer) $id; + + return $this->con->execute( + 'DELETE FROM '.$this->table.' '. + "WHERE blog_id='".$this->blog."' ". + "AND kut_id='".$id."' " + ); + } + + public function counter($id,$do='get') + { + $id = (integer) $id; + + $rs = $this->con->select( + 'SELECT kut_counter '. + 'FROM '.$this->table.' '. + "WHERE blog_id='".$this->blog."' ". + "AND kut_id='".$id."' " + ); + + $counter = $rs->isEmpty() ? 0 : $rs->kut_counter; + + if ('get' == $do) + { + return $counter; + } + elseif ('up' == $do) + { + $counter += 1; + } + elseif ('reset' == $do) + { + $counter = 0; + } + else + { + return 0; + } + + $cur = $this->con->openCursor($this->table); + $this->con->writeLock($this->table); + + $cur->kut_counter = (integer) $counter; + $cur->update( + "WHERE blog_id='".$this->blog."' ". + "AND kut_id='".$id."'" + ); + $this->con->unlock(); + + return $counter; + } + + public function getLogs($p,$count_only=false) + { + if ($count_only) + { + $r = 'SELECT count(S.kut_id) '; + } + else + { + $content_req = ''; + + if (!empty($p['columns']) && is_array($p['columns'])) + { + $content_req .= implode(', ',$p['columns']).', '; + } + $r = + 'SELECT S.kut_id, S.kut_type, S.kut_hash, S.kut_url, '. + $content_req.'S.kut_dt '; + } + + $r .= 'FROM '.$this->table.' S '; + + if (!empty($p['from'])) + { + $r .= $p['from'].' '; + } + $r .= "WHERE S.blog_id = '".$this->blog."' "; + + if (isset($p['kut_service'])) + { + $r .= "AND kut_service='".$this->con->escape($p['kut_service'])."' "; + } + else + { + $r .= "AND kut_service='kutrl' "; + } + + if (isset($p['kut_type'])) + { + if (is_array($p['kut_type']) && !empty($p['kut_type'])) + { + $r .= 'AND kut_type '.$this->con->in($p['kut_type']); + } + elseif ($p['kut_type'] != '') + { + $r .= "AND kut_type = '".$this->con->escape($p['kut_type'])."' "; + } + } + + if (isset($p['kut_id'])) + { + if (is_array($p['kut_id']) && !empty($p['kut_id'])) + { + $r .= 'AND kut_id '.$this->con->in($p['kut_id']); + } + elseif ($p['kut_id'] != '') + { + $r .= "AND kut_id = '".$this->con->escape($p['kut_id'])."' "; + } + } + + if (isset($p['kut_hash'])) + { + if (is_array($p['kut_hash']) && !empty($p['kut_hash'])) + { + $r .= 'AND kut_hash '.$this->con->in($p['kut_hash']); + } + elseif ($p['kut_hash'] != '') + { + $r .= "AND kut_hash = '".$this->con->escape($p['kut_hash'])."' "; + } + } + + if (isset($p['kut_url'])) + { + if (is_array($p['kut_url']) && !empty($p['kut_url'])) + { + $r .= 'AND kut_url '.$this->con->in($p['kut_url']); + } + elseif ($p['kut_url'] != '') + { + $r .= "AND kut_url = '".$this->con->escape($p['kut_url'])."' "; + } + } + + if (!empty($p['kut_year'])) + { + $r .= + 'AND '.$this->con->dateFormat('kut_dt','%Y').' = '. + "'".sprintf('%04d',$p['kut_year'])."' "; + } + + if (!empty($p['kut_month'])) + { + $r .= + 'AND '.$this->con->dateFormat('kut_dt','%m').' = '. + "'".sprintf('%02d',$p['kut_month'])."' "; + } + + if (!empty($p['kut_day'])) + { + $r .= + 'AND '.$this->con->dateFormat('kut_dt','%d').' = '. + "'".sprintf('%02d',$p['kut_day'])."' "; + } + + if (!empty($p['sql'])) + { + $r .= $p['sql'].' '; + } + + if (!$count_only) + { + $r .= empty($p['order']) ? + 'ORDER BY kut_dt DESC ' : + 'ORDER BY '.$this->con->escape($p['order']).' '; + } + + if (!$count_only && !empty($p['limit'])) + { + $r .= $this->con->limit($p['limit']); + } + + return $this->con->select($r); + } +} +?> \ No newline at end of file diff --git a/inc/lib.kutrl.srv.php b/inc/lib.kutrl.srv.php new file mode 100644 index 0000000..f4f53a8 --- /dev/null +++ b/inc/lib.kutrl.srv.php @@ -0,0 +1,254 @@ +core = $core; + $this->settings = $core->blog->settings->kUtRL; + $this->log = new kutrlLog($core); + $this->error = new dcError(); + $this->error->setHTMLFormat('%s',"%s\n"); + + $this->init(); + + // Force setting + $allow_external_url = $this->settings->kutrl_allow_external_url; + $this->config['$allow_external_url'] = null === $allow_external_url ? + true : $allow_external_url; + + $this->config = array_merge( + array( + 'id' => 'undefined', + 'name' => 'undefined', + 'home' => '', + + 'allow_external_url' => true, + 'allow_custom_hash' => false, + 'allow_protocols' => array('http://'), + + 'url_test' => 'http://dotclear.jcdenis.com/go/kUtRL', + 'url_api' => '', + 'url_base' => '', + 'url_min_len' => 0 + ), + $this->config + ); + } + + # Magic get for config values + public function __get($k) + { + return isset($this->config[$k]) ? $this->config[$k] : null; + } + + # Additionnal actions on child start + protected function init() + { + // + } + + # Save settings from admin page + public function saveSettings() + { + return null; + } + + # Settings form for admin page + public function settingsForm() + { + echo + '

    '. + __('There is nothing to configure for this service.'). + '

    '; + } + + # Test if service is well configured + public function testService() + { + return null; + } + + # Test if an url is valid + public function isValidUrl($url) + { + return (boolean) filter_var($url,FILTER_VALIDATE_URL); + } + + # Test if an url contents know prefix + public function isServiceUrl($url) + { + return strpos($url,$this->url_base) === 0; + } + + # Test if an url is long enoutgh + public function isLongerUrl($url) + { + return ((integer) $this->url_min_len >= $url); + } + + # Test if an url protocol (eg: http://) is allowed + public function isProtocolUrl($url) + { + foreach($this->allow_protocols as $protocol) + { + if (empty($protocol)) continue; + + if (strpos($url,$protocol) === 0) return true; + } + return false; + } + + # Test if an url is from current blog + public function isBlogUrl($url) + { + $base = $this->core->blog->url; + $url = substr($url,0,strlen($base)); + + return $url == $base; + } + + # Test if an url is know + public function isKnowUrl($url) + { + return $this->log->select($url,null,$this->id,'kutrl'); + } + + # Test if an custom short url is know + public function isKnowHash($hash) + { + return $this->log->select(null,$hash,$this->id,'kutrl'); + } + + # Create hash from url + public function hash($url,$hash=null) + { + $url = trim($this->core->con->escape($url)); + if ('undefined' === $this->id) + { + return false; + } + if ($hash && !$this->allow_custom_hash) + { + return false; + } + if ($this->isServiceUrl($url)) + { + return false; + } + if (!$this->isLongerUrl($url)) + { + return false; + } + if (!$this->allow_external_url && $this->isBlogUrl($url)) + { + return false; + } + if ($hash && false !== ($rs = $this->isKnowHash($hash))) + { + return false; + } + if (false === ($rs = $this->isKnowUrl($url))) + { + if (false === ($rs = $this->createHash($url,$hash))) + { + return false; + } + + $this->log->insert($rs->url,$rs->hash,$rs->type,'kutrl'); + $this->core->blog->triggerBlog(); + + + # --BEHAVIOR-- kutrlAfterCreateShortUrl + $this->core->callBehavior('kutrlAfterCreateShortUrl',$rs); + + + } + return $rs; + } + + # Create a hash for a given url (and its custom hash) + public function createHash($url,$hash=null) + { + return false; + } + + # Remove an url from list of know urls + public function remove($url) + { + if (!($rs = $this->isKnowUrl($url))) return false; + echo 'la'; + $this->deleteUrl($url); + $this->log->delete($rs->id); + return true; + } + + # Delete url on service (second argument really delete urls) + public function deleteUrl($url,$delete=false) + { + return null; + } + + # Retrieve long url from hash + public function getUrl($hash) + { + return false; + } + + # Post request + public static function post($server,$data,$verbose=true,$get=false,$headers=array()) + { + $url = (string) $server; + $client = netHttp::initClient($url,$url); + $client->setUserAgent('kUtRL - http://kutrl.fr'); + $client->setPersistReferers(false); + + if (is_array($headers) && !empty($headers)) + { + foreach($headers as $header) + { + $client->setMoreHeader($header); + } + } + + if ($get) + { + $client->get($url,$data); + } + else + { + $client->post($url,$data); + } + + if (!$verbose && $client->getStatus() != 200) + { + return false; + } + + if ($verbose) + { + return $client->getContent(); + } + return true; + } +} +?> \ No newline at end of file diff --git a/inc/lib.wiki.kutrl.php b/inc/lib.wiki.kutrl.php new file mode 100644 index 0000000..96ee948 --- /dev/null +++ b/inc/lib.wiki.kutrl.php @@ -0,0 +1,80 @@ +blog->settings->kUtRL; + + # Do nothing on comment preview and post preview + if (!empty($_POST['preview']) + || !empty($GLOBALS['_ctx']) && $GLOBALS['_ctx']->preview + || !$s->kutrl_active) return; + + if (null === ($kut = kutrl::quickPlace('wiki'))) return; + + foreach($kut->allow_protocols as $protocol) + { + $wiki2xhtml->registerFunction( + 'url:'.$protocol, + array('kutrlWiki','transform') + ); + } + } + + public static function transform($url,$content) + { + global $core; + $s = $core->blog->settings->kUtRL; + + if (!$s->kutrl_active) return; + + if (null === ($kut = kutrl::quickPlace('wiki'))) return array(); + + # Test if long url exists + $is_new = false; + $rs = $kut->isKnowUrl($url); + if (!$rs) + { + $is_new = true; + $rs = $kut->hash($url); + } + + if (!$rs) + { + return array(); + } + else + { + $res = array(); + $testurl = strlen($rs->url) > 35 ? substr($rs->url,0,35).'...' : $rs->url; + $res['url'] = $kut->url_base.$rs->hash; + $res['title'] = sprintf(__('%s (Shorten with %s)'),$rs->url,__($kut->name)); + if ($testurl == $content) $res['content'] = $res['url']; + + # ex: Send new url to messengers + if (!empty($rs)) + { + $core->callBehavior('wikiAfterKutrlCreate',$core,$rs,__('New short URL')); + } + + return $res; + } + } +} +?> \ No newline at end of file diff --git a/inc/patch.dcminiurl.php b/inc/patch.dcminiurl.php new file mode 100644 index 0000000..42a7561 --- /dev/null +++ b/inc/patch.dcminiurl.php @@ -0,0 +1,135 @@ +parseRecords()) +{ + try + { + $core->plugins->deactivateModule('dcMiniUrl'); + } + catch (Exception $e) + { + //$core->error->add($e->getMessage()); + } +} + +class dcMiniUrl2kUtRL +{ + public $core; + + public $k_tb; + public $m_tb; + + public function __construct($core) + { + $this->core = $core; + $this->con = $core->con; + $this->k_tb = $core->prefix.'kutrl'; + $this->m_tb = $core->prefix.'miniurl'; + } + + public function parseRecords() + { + $rs = $this->con->select( + 'SELECT * FROM '.$this->m_tb.' ' + ); + + while ($rs->fetch()) + { + if ($rs->miniurl_type == 'customurl' || $rs->miniurl_type == 'miniurl') + { + if ($this->exists($rs)) continue; + + $this->insertKutrl($rs); + $this->insertLocal($rs); + } + else + { + $this->insertOther($rs); + } + } + return true; + } + + private function insertKutrl($rs) + { + $cur = $this->common($rs); + $cur->kut_service = 'kutrl'; + $cur->kut_type = 'local'; + $cur->kut_counter = 0; + $cur->kut_password = null; + + $cur->insert(); + $this->con->unlock(); + } + + private function insertLocal($rs) + { + $cur = $this->common($rs); + $cur->kut_service = 'local'; + $cur->kut_type = $rs->miniurl_type == 'customurl' ? + 'localcustom' : 'localnormal'; + + $cur->insert(); + $this->con->unlock(); + } + + private function insertOther($rs) + { + $cur = $this->common($rs); + + $cur->insert(); + $this->con->unlock(); + } + + private function common($rs) + { + $cur = $this->con->openCursor($this->k_tb); + $this->con->writeLock($this->k_tb); + $cur->kut_id = $this->nextId(); + $cur->blog_id = $rs->blog_id; + $cur->kut_service = 'unknow'; + $cur->kut_type = $rs->miniurl_type; + $cur->kut_hash = $rs->miniurl_id; + $cur->kut_url = $rs->miniurl_str; + $cur->kut_dt = $rs->miniurl_dt; + $cur->kut_counter = $rs->miniurl_counter; + $cur->kut_password = $rs->miniurl_password; + + return $cur; + } + + private function exists($rs) + { + $chk = $this->con->select( + 'SELECT kut_hash FROM '.$this->k_tb.' '. + "WHERE blog_id = '".$rs->blog_id."' ". + "AND kut_service = 'local' ". + "AND kut_hash = '".$rs->miniurl_id."' " + ); + return !$chk->isEmpty(); + } + + private function nextId() + { + return $this->con->select( + 'SELECT MAX(kut_id) FROM '.$this->k_tb.' ' + )->f(0) + 1; + } +} +?> \ No newline at end of file diff --git a/inc/services/class.bilbolinks.service.php b/inc/services/class.bilbolinks.service.php new file mode 100644 index 0000000..f1eac24 --- /dev/null +++ b/inc/services/class.bilbolinks.service.php @@ -0,0 +1,97 @@ + 'bilbolinks', + 'name' => 'BilboLinks', + 'home' => 'http://www.tux-planet.fr/bilbobox/' + ); + + protected function init() + { + $base = (string) $this->settings->kutrl_srv_bilbolinks_base; + if (!empty($base) && substr($base,-1,1) != '/') $base .= '/'; + + $this->config['url_api'] = $base.'api.php'; + $this->config['url_base'] = $base; + $this->config['url_min_len'] = 25; + } + + public function saveSettings() + { + $base = ''; + if (!empty($_POST['kutrl_srv_bilbolinks_base'])) + { + $base = $_POST['kutrl_srv_bilbolinks_base']; + if (substr($base,-1,1) != '/') $base .= '/'; + } + + $this->settings->put('kutrl_srv_bilbolinks_base',$base); + } + + public function settingsForm() + { + echo + '

    '. + '

    '. + __('This is the root URL of the "bilbolinks" service you want to use. Ex: "http://tux-pla.net/".'). + '

    '; + } + + public function testService() + { + if (empty($this->url_base)) + { + $this->error->add(__('Service is not well configured.')); + return false; + } + + $arg = array('longurl' => urlencode($this->url_test)); + if (!self::post($this->url_api,$arg,true,true)) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + return true; + } + + public function createHash($url,$hash=null) + { + $arg = array('longurl' => $url); + + if (!($response = self::post($this->url_api,$arg,true,true))) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + if ($response == 'You are too speed!') + { + $this->error->add(__('Service rate limit exceeded.')); + return false; + } + + $rs = new ArrayObject(); + $rs->hash = str_replace($this->url_base,'',$response); + $rs->url = $url; + $rs->type = $this->id; + + return $rs; + } +} +?> \ No newline at end of file diff --git a/inc/services/class.bitly.service.php b/inc/services/class.bitly.service.php new file mode 100644 index 0000000..235a978 --- /dev/null +++ b/inc/services/class.bitly.service.php @@ -0,0 +1,127 @@ + 'bitly', + 'name' => 'bit.ly', + 'home' => 'http://bit.ly', + + 'url_api' => 'http://api.bit.ly/v3/', + 'url_base' => 'http://bit.ly/', + 'url_min_len' => 25 + ); + + private $args = array( + 'format' => 'xml', + 'login' => '', + 'apiKey' => '', + 'history' => 0 + ); + + protected function init() + { + $this->args['login'] = $this->settings->kutrl_srv_bitly_login; + $this->args['apiKey'] = $this->settings->kutrl_srv_bitly_apikey; + $this->args['history'] = $this->settings->kutrl_srv_bitly_history ? 1 : 0; + } + + public function saveSettings() + { + $this->settings->put('kutrl_srv_bitly_login',$_POST['kutrl_srv_bitly_login']); + $this->settings->put('kutrl_srv_bitly_apikey',$_POST['kutrl_srv_bitly_apikey']); + $this->settings->put('kutrl_srv_bitly_history',isset($_POST['kutrl_srv_bitly_history'])); + } + + public function settingsForm() + { + echo + '

    '. + '

    '. + sprintf(__('This is your login to sign up to %s'),$this->config['name']). + '

    '. + '

    '. + '

    '. + sprintf(__('This is your personnal %s API key. You can find it on your account page.'),$this->config['name']). + '

    '. + '

    '. + '

    '. + __('This publish all short links on your bit.ly public page.'). + '

    '; + } + + public function testService() + { + if (empty($this->args['login']) || empty($this->args['apiKey'])) + { + $this->error->add(__('Service is not well configured.')); + return false; + } + + $args = $this->args; + $args['hash'] = 'WP9vc'; + if (!($response = self::post($this->url_api.'expand',$args,true))) + { + $this->error->add(__('Failed to call service.')); + return false; + } + + $rsp = simplexml_load_string($response); + + $err_msg = (string) $rsp->status_txt; + if ($err_msg != 'OK') { + $err_no = (integer) $rsp->status_code; + $this->error->add(sprintf(__('An error occured with code %s and message "%s"'),$err_no,$err_msg)); + return false; + } + return true; + } + + public function createHash($url,$hash=null) + { + $args = $this->args; + $args['longUrl'] = $url; + + if (!($response = self::post($this->url_api.'shorten',$args,true))) + { + $this->error->add(__('Failed to call service.')); + return false; + } + + $rsp = simplexml_load_string($response); + + $err_msg = (string) $rsp->status_txt; + if ($err_msg != 'OK') { + $err_no = (integer) $rsp->status_code; + $this->error->add(sprintf(__('An error occured with code %s and message "%s"'),$err_no,$err_msg)); + return false; + } + + $rs = new ArrayObject(); + $rs->hash = (string) $rsp->data[0]->hash; + $rs->url = (string) $rsp->data[0]->long_url; + $rs->type = $this->id; + + return $rs; + } +} +?> \ No newline at end of file diff --git a/inc/services/class.custom.service.php b/inc/services/class.custom.service.php new file mode 100644 index 0000000..449d25b --- /dev/null +++ b/inc/services/class.custom.service.php @@ -0,0 +1,120 @@ + 'custom', + 'name' => 'Custom' + ); + + protected function init() + { + $config = unserialize(base64_decode($this->settings->kutrl_srv_custom)); + if (!is_array($config)) + { + $config = array(); + } + + $this->config['url_api'] = !empty($config['url_api']) ? $config['url_api'] : ''; + $this->config['url_base'] = !empty($config['url_base']) ? $config['url_base'] : ''; + $this->config['url_param'] = !empty($config['url_param']) ? $config['url_param'] : ''; + $this->config['url_encode'] = !empty($config['url_api']); + + $this->config['url_min_length'] = strlen($this->url_base) + 2; + } + + public function saveSettings() + { + $config = array( + 'url_api' => $_POST['kutrl_srv_custom_url_api'], + 'url_base' => $_POST['kutrl_srv_custom_url_base'], + 'url_param' => $_POST['kutrl_srv_custom_url_param'], + 'url_encode' => !empty($_POST['kutrl_srv_custom_url_encode']) + ); + $this->settings->put('kutrl_srv_custom',base64_encode(serialize($config))); + } + + public function settingsForm() + { + $default = array( + 'url_api' => '', + 'url_base' => '', + 'url_param' => '', + 'url_encode' => true + ); + $config = unserialize(base64_decode($this->settings->kutrl_srv_custom)); + if (!is_array($config)) + { + $config = array(); + } + $config = array_merge($default,$config); + + echo + '

    '.__('You can set a configurable service.').'
    '. + __('It consists on a simple query to an URL with only one param.').'
    '. + __('It must respond with a http code 200 on success.').'
    '. + __('It must returned the short URL (or only hash) in clear text.').'

    ' . + '

    '. + '

    '.__('Full path to API of the URL shortener. ex: "http://is.gd/api.php"').'

    '. + '

    '. + '

    '.__('Common part of the short URL. ex: "http://is.gd/"').'

    '. + '

    '. + '

    '.__('Param of the query. ex: "longurl"').'

    '. + '

    '; + } + + public function testService() + { + if (empty($this->url_api)) return false; + + $url = $this->url_encode ? urlencode($this->url_test) : $this->url_test; + $arg = array($this->url_param => $url); + if (!self::post($this->url_api,$arg,true,true)) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + return true; + } + + public function createHash($url,$hash=null) + { + $enc = $this->url_encode ? urlencode($url) : $url; + $arg = array($this->url_param => $enc); + + if (!($response = self::post($this->url_api,$arg,true,true))) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + + $rs = new ArrayObject(); + $rs->hash = str_replace($this->url_base,'',$response); + $rs->url = $url; + $rs->type = $this->id; + + return $rs; + } +} +?> \ No newline at end of file diff --git a/inc/services/class.default.service.php b/inc/services/class.default.service.php new file mode 100644 index 0000000..1f71056 --- /dev/null +++ b/inc/services/class.default.service.php @@ -0,0 +1,91 @@ +config = array( + 'id' => 'default', + 'name' => 'Default', + 'home' => '', + + 'url_api' => SHORTEN_SERVICE_API, + 'url_base' => SHORTEN_SERVICE_BASE, + 'url_min_len' => strlen(SHORTEN_SERVICE_BASE) + 2, + + 'url_param' => SHORTEN_SERVICE_PARAM, + 'url_encode' => SHORTEN_SERVICE_ENCODE + ); + } + + public function settingsForm() + { + echo + '

    '. + __('There is nothing to configure for this service.'). + '

    '. + '

    '.__('This service is set to:').'

    '. + '
    '. + '
    '.__('Service name:').'
    '. + '
    '.SHORTEN_SERVICE_NAME.'
    '. + '
    '.__('Full API URL:').'
    '. + '
    '.SHORTEN_SERVICE_API.'
    '. + '
    '.__('Query param:').'
    '. + '
    '.SHORTEN_SERVICE_PARAM.'
    '. + '
    '.__('Short URL domain:').'
    '. + '
    '.SHORTEN_SERVICE_BASE.'
    '. + '
    '.__('Encode URL:').'
    '. + '
    '.(SHORTEN_SERVICE_ENCODE ? __('yes') : __('no')).'
    '. + '
    '; + } + + public function testService() + { + $url = $this->url_encode ? urlencode($this->url_test) : $this->url_test; + $arg = array($this->url_param => urlencode($this->url_test)); + + if (!self::post($this->url_api,$arg,true,true)) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + return true; + } + + public function createHash($url,$hash=null) + { + $enc = $this->url_encode ? urlencode($url) : $url; + $arg = array($this->url_param => $url); + + if (!($response = self::post($this->url_api,$arg,true,true))) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + + $rs = new ArrayObject(); + $rs->hash = str_replace($this->url_base,'',$response); + $rs->url = $url; + $rs->type = $this->id; + + return $rs; + } +} +?> \ No newline at end of file diff --git a/inc/services/class.googl.service.php b/inc/services/class.googl.service.php new file mode 100644 index 0000000..5a175e1 --- /dev/null +++ b/inc/services/class.googl.service.php @@ -0,0 +1,80 @@ + 'AIzaSyDE1WfOMdnrnX8p51jSmVodenaNk385asc' + ); + private $headers = array('Content-Type: application/json'); + + protected function init() + { + $this->url_base = 'http://goo.gl/'; + $this->url_min_length = 20; + } + + public function testService() + { + $args = $this->args; + $args['shortUrl'] = $this->url_base.'PLovn'; + if (!($response = self::post($this->url_api,$args,true,true,$this->headers))) + { + $this->error->add(__('Failed to call service.')); + return false; + } + + $rsp = json_decode($response); + + if (empty($rsp->status)) { + $this->error->add(__('An error occured')); + return false; + } + return true; + } + + public function createHash($url,$hash=null) + { + $args = $this->args; + $args['longUrl'] = $url; + $args = json_encode($args); + + if (!($response = self::post($this->url_api,$args,true,false,$this->headers))) + { + $this->error->add(__('Failed to call service.')); + return false; + } + + $rsp = json_decode($response); + + if (empty($rsp->id)) { + $this->error->add(__('An error occured')); + return false; + } + + $rs = new ArrayObject(); + $rs->hash = str_replace($this->url_base,'',$rsp->id); + $rs->url = $rsp->longUrl; + $rs->type = $this->id; + + return $rs; + } +} +?> \ No newline at end of file diff --git a/inc/services/class.isgd.service.php b/inc/services/class.isgd.service.php new file mode 100644 index 0000000..62ef7e6 --- /dev/null +++ b/inc/services/class.isgd.service.php @@ -0,0 +1,56 @@ + 'isgd', + 'name' => 'is.gd', + 'home' => 'http://is.gd/', + + 'url_api' => 'http://is.gd/api.php', + 'url_base' => 'http://is.gd/', + 'url_min_length' => 25 + ); + + public function testService() + { + $arg = array('longurl' => urlencode($this->url_test)); + if (!self::post($this->url_api,$arg,true,true)) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + return true; + } + + public function createHash($url,$hash=null) + { + $arg = array('longurl' => $url); + + if (!($response = self::post($this->url_api,$arg,true,true))) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + + $rs = new ArrayObject(); + $rs->hash = str_replace($this->url_base,'',$response); + $rs->url = $url; + $rs->type = $this->id; + + return $rs; + } +} +?> \ No newline at end of file diff --git a/inc/services/class.local.service.php b/inc/services/class.local.service.php new file mode 100644 index 0000000..6334a32 --- /dev/null +++ b/inc/services/class.local.service.php @@ -0,0 +1,270 @@ + 'local', + 'name' => 'kUtRL', + 'home' => 'http://kutrl.fr', + + 'allow_custom_hash' => true + ); + + protected function init() + { + $protocols = (string) $this->settings->kutrl_srv_local_protocols; + $this->config['allow_protocols'] = empty($protocols) ? array() : explode(',',$protocols); + + $this->config['url_base'] = $this->core->blog->url.$this->core->url->getBase('kutrl').'/'; + $this->config['url_min_len'] = strlen($this->url_base) + 2; + + } + + public function saveSettings() + { + $this->settings->put('kutrl_srv_local_protocols',$_POST['kutrl_srv_local_protocols'],'string'); + $this->settings->put('kutrl_srv_local_public',isset($_POST['kutrl_srv_local_public']),'boolean'); + $this->settings->put('kutrl_srv_local_css',$_POST['kutrl_srv_local_css'],'string'); + $this->settings->put('kutrl_srv_local_404_active',isset($_POST['kutrl_srv_local_404_active']),'boolean'); + } + + public function settingsForm() + { + echo + '
    '. + + '

    '.__('Settings:').'

    '. + '

    '. + + '

    '. + __('Use comma seperated list like: "http:,https:,ftp:"'). + '

    '. + + '

    '. + + '

    '. + form::textarea('kutrl_srv_local_css',50,3,html::escapeHTML($this->settings->kutrl_srv_local_css),'',2). + '

    '. + '

    '.__('You can add here special cascading style sheet. Body of page has class "dc-kutrl" and widgets have class "shortenkutrlwidget" and "rankkutrlwidget".').'

    '. + + '

    '. + '

    '.__('If this is not activated, the default 404 page of the theme will be display.').'

    '. + + '
    '. + + '

    '.__('Note:').'

    '. + '

    '. + __('This service use your own Blog to shorten and serve URL.').'
    '. + sprintf(__('This means that with this service short links start with "%s".'),$this->url_base). + '

    '. + '

    '. + __("You can use Dotclear's plugin called myUrlHandlers to change short links prefix on your blog."); + + if (preg_match('/index\.php/',$this->url_base)) + { + echo + '

    '. + __("We recommand that you use a rewrite engine in order to remove 'index.php' from your blog's URL."). + '
    '. + __("You can find more about this on the Dotclear's documentation."). + '

    '; + } + echo + '

    '. + '

    '.__('There are two templates delivered with kUtRL, if you do not use default theme, you may adapt them to yours.').'
    '. + __('Files are in plugin directory /default-templates, just copy them into your theme and edit them.').'

    '. + + '
    '; + } + + public function testService() + { + if (!empty($this->allow_protocols)) + { + return true; + } + else { + $this->error->add(__('Service is not well configured.')); + return false; + } + } + + public function createHash($url,$hash=null) + { + # Create response object + $rs = new ArrayObject(); + $rs->type = 'local'; + $rs->url = $url; + + # Normal link + if ($hash === null) + { + $type = 'localnormal'; + $rs->hash = $this->next($this->last('localnormal')); + } + + # Mixed custom link + elseif (preg_match('/^([A-Za-z0-9]{2,})\!\!$/',$hash,$m)) + { + $type = 'localmix'; + $rs->hash = $m[1].$this->next(-1,$m[1]); + } + + # Custom link + elseif (preg_match('/^[A-Za-z0-9\.\-\_]{2,}$/',$hash)) + { + if (false !== $this->log->select(null,$hash,null,'local')) + { + $this->error->add(__('Custom short link is already taken.')); + return false; + } + $type = 'localcustom'; + $rs->hash = $hash; + } + + # Wrong char in custom hash + else + { + $this->error->add(__('Custom short link is not valid.')); + return false; + } + + # Save link + try { + $this->log->insert($rs->url,$rs->hash,$type,$rs->type); + return $rs; + } + catch (Exception $e) + { + $this->error->add(__('Failed to save link.')); + } + return false; + } + + protected function last($type) + { + return + false === ($rs = $this->log->select(null,null,$type,'local')) ? + -1 : $rs->hash; + } + + protected function next($last_id,$prefix='') + { + if ($last_id == -1) + { + $next_id = 0; + } + else + { + for($x = 1; $x <= strlen($last_id); $x++) + { + $pos = strlen($last_id) - $x; + + if ($last_id[$pos] != 'z') + { + $next_id = $this->increment($last_id,$pos); + break; + } + } + + if (!isset($next_id)) + { + $next_id = $this->append($last_id); + } + } + + return + false === $this->log->select(null,$prefix.$next_id,null,'local') ? + $next_id : $this->next($next_id,$prefix); + } + + protected function append($id) + { + $id = str_split($id); + for ($x = 0; $x < count($id); $x++) + { + $id[$x] = 0; + } + return implode($id).'0'; + } + + protected function increment($id,$pos) + { + $id = str_split($id); + $char = $id[$pos]; + + if (is_numeric($char)) + { + $new_char = $char < 9 ? $char + 1 : 'a'; + } + else + { + $new_char = chr(ord($char) + 1); + } + $id[$pos] = $new_char; + + if ($pos != (count($id) - 1)) + { + for ($x = ($pos + 1); $x < count($id); $x++) + { + $id[$x] = 0; + } + } + + return implode($id); + } + + public function getUrl($hash) + { + if (false === ($rs = $this->log->select(null,$hash,null,'local'))) + { + return false; + } + if (!$rs->url) //previously removed url + { + return false; + } + + $this->log->counter($rs->id,'up'); + return $rs->url; + } + + public function deleteUrl($url,$delete=false) + { + if (false === ($rs = $this->log->select($url,null,null,'local'))) + { + return false; + } + if ($delete) + { + $this->log->delete($rs->id); + } + else + { + $this->log->clear($rs->id,''); + } + return true; + } +} +?> \ No newline at end of file diff --git a/inc/services/class.shortto.service.php b/inc/services/class.shortto.service.php new file mode 100644 index 0000000..8559608 --- /dev/null +++ b/inc/services/class.shortto.service.php @@ -0,0 +1,56 @@ + 'shortto', + 'name' => 'short.to', + 'home' => 'http://short.to', + + 'url_api' => 'http://short.to/s.txt', + 'url_base' => 'http://short.to/', + 'url_min_len' => 25 + ); + + public function testService() + { + $arg = array('url' => urlencode($this->url_test)); + if (!self::post($this->url_api,$arg,true,true)) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + return true; + } + + public function createHash($url,$hash=null) + { + $arg = array('url' => $url); + + if (!($response = self::post($this->url_api,$arg,true,true))) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + + $rs = new ArrayObject(); + $rs->hash = str_replace($this->url_base,'',$response); + $rs->url = $url; + $rs->type = $this->id; + + return $rs; + } +} +?> \ No newline at end of file diff --git a/inc/services/class.supr.service.php b/inc/services/class.supr.service.php new file mode 100644 index 0000000..3858d84 --- /dev/null +++ b/inc/services/class.supr.service.php @@ -0,0 +1,120 @@ + 'supr', + 'name' => 'su.pr StumbleUpon', + 'home' => 'http://su.pr', + + 'url_api' => 'http://su.pr/api/', + 'url_base' => 'http://su.pr/', + 'url_min_len' => 23 + ); + + private $args = array( + 'version' => '1.0', + 'format' => 'xml', + 'login' => '', + 'apiKey' => '' + ); + + protected function init() + { + $this->args['login'] = $this->settings->kutrl_srv_supr_login; + $this->args['apiKey'] = $this->settings->kutrl_srv_supr_apikey; + } + + public function saveSettings() + { + $this->settings->put('kutrl_srv_supr_login',$_POST['kutrl_srv_supr_login']); + $this->settings->put('kutrl_srv_supr_apikey',$_POST['kutrl_srv_supr_apikey']); + } + + public function settingsForm() + { + echo + '

    '. + '

    '. + sprintf(__('This is your login to sign up to %s'),$this->config['name']). + '

    '. + '

    '. + '

    '. + sprintf(__('This is your personnal %s API key. You can find it on your account page.'),$this->config['name']). + '

    '; + } + + public function testService() + { + if (empty($this->args['login']) || empty($this->args['apiKey'])) + { + $this->error->add(__('Service is not well configured.')); + return false; + } + + $args = $this->args; + $arg['longUrl'] = $this->url_test; + if (!($response = self::post($this->url_api.'shorten',$args,true))) + { + $this->error->add(__('Failed to call service.')); + return false; + } + + $rsp = simplexml_load_string($response); + + $status = (string) $rsp->statusCode; + if ($status != 'OK') { + $err_no = (integer) $rsp->errorCode; + $err_msg = (integer) $rsp->errorMessage; + $this->error->add(sprintf(__('An error occured with code %s and message "%s"'),$err_no,$err_msg)); + return false; + } + return true; + } + + public function createHash($url,$hash=null) + { + $args = $this->args; + $args['longUrl'] = $url; + + if (!($response = self::post($this->url_api.'shorten',$args,true))) + { + $this->error->add(__('Failed to call service.')); + return false; + } + + $rsp = simplexml_load_string($response); + + $status = (string) $rsp->statusCode; + if ($status != 'OK') { + $err_no = (integer) $rsp->errorCode; + $err_msg = (integer) $rsp->errorMessage; + $this->error->add(sprintf(__('An error occured with code %s and message "%s"'),$err_no,$err_msg)); + return false; + } + + $rs = new ArrayObject(); + $rs->hash = (string) $rsp->results[0]->nodeKeyVal->hash; + $rs->url = (string) $rsp->results[0]->nodeKeyVal->nodeKey; + $rs->type = $this->id; + + return $rs; + } +} +?> \ No newline at end of file diff --git a/inc/services/class.trim.service.php b/inc/services/class.trim.service.php new file mode 100644 index 0000000..fe2c755 --- /dev/null +++ b/inc/services/class.trim.service.php @@ -0,0 +1,126 @@ + 'trim', + 'name' => 'tr.im', + 'home' => 'http://tr.im', + + 'url_api' => 'http://api.tr.im/v1/', + 'url_base' => 'http://tr.im/', + 'url_min_len' => 25 + ); + + private $args = array( + 'username' => '', + 'password' => '' + ); + + private $api_rate_time = 0; + + protected function init() + { + $this->args['username'] = $this->settings->kutrl_srv_trim_username; + $this->args['password'] = $this->settings->kutrl_srv_trim_password; + + $this->api_rate_time = (integer) $this->settings->kutrl_srv_trim_apiratetime; + } + + public function saveSettings() + { + $this->settings->put('kutrl_srv_trim_username',$_POST['kutrl_srv_trim_username']); + $this->settings->put('kutrl_srv_trim_password',$_POST['kutrl_srv_trim_password']); + } + + public function settingsForm() + { + echo + '

    '. + '

    '. + __('This is your login to sign up to tr.im.'). + '

    '. + '

    '. + '

    '. + __('This is your password to sign up to tr.im.'). + '

    '; + } + + public function testService() + { + if (empty($this->args['username']) || empty($this->args['password'])) + { + $this->error->add(__('Service is not well configured.')); + return false; + } + if (time() < $this->api_rate_time + 300) // bloc service within 5min on API rate limit + { + $this->error->add(__('Prevent service rate limit.')); + return false; + } + if (!($rsp = self::post($this->url_api.'verify.xml',$this->args,true,true))) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + $r = simplexml_load_string($rsp); + + if ($r['code'] == 200) + { + return true; + } + $this->error->add(__('Authentication to service failed.')); + return false; + } + + public function createHash($url,$hash=null) + { + $arg = $this->args; + $arg['url'] = $url; + + if (!($rsp = self::post($this->url_api.'trim_url.xml',$arg,true,true))) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + + $r = simplexml_load_string($rsp); + + # API rate limit + if ($r['code'] == 425) + { + $this->settings->put('kutrl_srv_trim_apiratetime',time()); + + $this->error->add(__('Service rate limit exceeded.')); + return false; + } + if (isset($r->trimpath)) + { + $rs = new ArrayObject(); + $rs->hash = $r->trimpath; + $rs->url = $url; + $rs->type = $this->id; + + return $rs; + } + $this->error->add(__('Unreadable service response.')); + return false; + } +} +?> \ No newline at end of file diff --git a/inc/services/class.yourls.service.php b/inc/services/class.yourls.service.php new file mode 100644 index 0000000..4c847dc --- /dev/null +++ b/inc/services/class.yourls.service.php @@ -0,0 +1,126 @@ + 'yourls', + 'name' => 'YOURLS', + 'home' => 'http://yourls.org' + ); + + private $args = array( + 'username' => '', + 'password' => '', + 'format' => 'xml', + 'action' => 'shorturl' + ); + + protected function init() + { + $this->args['username'] = $this->settings->kutrl_srv_yourls_username; + $this->args['password'] = $this->settings->kutrl_srv_yourls_password; + + $base = (string) $this->settings->kutrl_srv_yourls_base; + //if (!empty($base) && substr($base,-1,1) != '/') $base .= '/'; + + $this->config['url_api'] = $base; + $this->config['url_base'] = $base; + $this->config['url_min_len'] = strlen($base)+3; + } + + public function saveSettings() + { + $this->settings->put('kutrl_srv_yourls_username',$_POST['kutrl_srv_yourls_username']); + $this->settings->put('kutrl_srv_yourls_password',$_POST['kutrl_srv_yourls_password']); + $this->settings->put('kutrl_srv_yourls_base',$_POST['kutrl_srv_yourls_base']); + } + + public function settingsForm() + { + echo + '

    '. + '

    '. + __('This is the URL of the YOURLS service you want to use. Ex: "http://www.smaller.org/api.php".'). + '

    '. + '

    '. + '

    '. + __('This is your user name to sign up to this YOURLS service.'). + '

    '. + '

    '. + '

    '. + __('This is your password to sign up to this YOURLS service.'). + '

    '; + } + + public function testService() + { + if (empty($this->url_api)) + { + $this->error->add(__('Service is not well configured.')); + return false; + } + + $args = $this->args; + $args['url'] = $this->url_test; + + if (!($response = self::post($this->url_api,$this->args,true))) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + $rsp = @simplexml_load_string($response); + + if ($rsp && $rsp->status == 'success') + { + return true; + } + $this->error->add(__('Authentication to service failed.')); + return false; + } + + public function createHash($url,$hash=null) + { + $args = $this->args; + $args['url'] = $url; + + if (!($response = self::post($this->url_api,$args,true))) + { + $this->error->add(__('Service is unavailable.')); + return false; + } + + $rsp = @simplexml_load_string($response); + + if ($rsp && $rsp->status == 'success') + { + $rs = new ArrayObject(); + $rs->hash = $rsp->url[0]->keyword; + $rs->url = $url; + $rs->type = $this->id; + + return $rs; + } + $this->error->add(__('Unreadable service response.')); + return false; + } +} +?> \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..cf2e720 --- /dev/null +++ b/index.php @@ -0,0 +1,70 @@ +blog->settings->kUtRL; + +# Default values +$show_filters = false; +$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : ''; +$section = isset($_REQUEST['section']) ? $_REQUEST['section'] : ''; +$img_green = 'ok'; +$img_red = 'fail'; + +$header = +dcPage::jsLoad('index.php?pf=kUtRL/js/main.js'). +'\n". +''; + +$footer = '

    +'.__('Settings').' - +'.__('Services').' - +kUtRL - '.$core->plugins->moduleInfo('kUtRL','version').'  +'.__('kUtRL').' +

    +

    + kUtRL, '.__('Links shortener').' | http://kutrl.fr +

    +'; + +# Messages +$msg = isset($_REQUEST['msg']) ? $_REQUEST['msg'] : ''; +$msg_list = array( + 'savesetting' => __('Configuration successfully saved'), + 'saveservice' => __('Services successfully updated'), + 'createlink' => __('Link successfully shorten'), + 'deletelinks' => __('Links successfully deleted') +); +if (isset($msg_list[$msg])) { + $msg = sprintf('

    %s

    ',$msg_list[$msg]); +} + +# Pages +$start_part = $s->kutrl_active ? 'links' : 'setting'; +$default_part = isset($_REQUEST['part']) ? $_REQUEST['part'] : $start_part; + +if (!file_exists(dirname(__FILE__).'/inc/index.'.$default_part.'.php')) { + $default_part = 'setting'; +} +include dirname(__FILE__).'/inc/index.'.$default_part.'.php'; + +?> \ No newline at end of file diff --git a/js/admin.js b/js/admin.js new file mode 100644 index 0000000..e8101b4 --- /dev/null +++ b/js/admin.js @@ -0,0 +1,15 @@ +/* -- BEGIN LICENSE BLOCK ---------------------------------- + * This file is part of kUtRL, a plugin for Dotclear 2. + * + * Copyright (c) 2009-2011 JC Denis and contributors + * jcdenis@gdwd.com + * + * Licensed under the GPL version 2.0 license. + * A copy of this license is available in LICENSE file or at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * -- END LICENSE BLOCK ------------------------------------*/ + +$(function(){ + /* toogle admin form sidebar */ + $('#kutrl-form-title').toggleWithLegend($('#kutrl-form-content'),{cookie:'dcx_kutrl_admin_form_sidebar'}); +}); \ No newline at end of file diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..8d0d5c9 --- /dev/null +++ b/js/main.js @@ -0,0 +1,80 @@ +/* -- BEGIN LICENSE BLOCK ---------------------------------- + * This file is part of kUtRL, a plugin for Dotclear 2. + * + * Copyright (c) 2009-2011 JC Denis and contributors + * jcdenis@gdwd.com + * + * Licensed under the GPL version 2.0 license. + * A copy of this license is available in LICENSE file or at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * -- END LICENSE BLOCK ------------------------------------*/ + +$(function(){ + /* tools */ + dotclear.jcTools = new jcToolsBox(); + /* wait message */ + $('#content').submit(function(){dotclear.jcTools.waitMessage();return true;}); +}); + +function jcToolsBox(){} + +jcToolsBox.prototype={ + text_wait:'Please wait', + section:'', + + formFieldsetToMenu:function(form){ + var This=this; + var section=$(form).children('fieldset[id='+This.section+']').attr('id'); + var hidden_section=$(form).children('input[name=section]').attr('value'); + var formMenu=$(form).children('p.formMenu').get(0); + if (formMenu==undefined) { + $(form).prepend($('

    ').addClass('formMenu')); + } + $(form).children('fieldset').each(function(){ + var Fieldset=this; + $(Fieldset).hide(); + var title=$(Fieldset).children('legend').text(); + var menu=$('').text(title).addClass('button').attr('tabindex','2').click( + function(){ + var fieldset_visible=$(form).children('fieldset:visible'); + if (fieldset_visible==undefined){ + $(Fieldset).slideDown('slow');$(form).children('input[type=submit]').show(); + }else{ + $(fieldset_visible).fadeOut('fast',function(){$(Fieldset).fadeIn('fast');$(form).children('input[type=submit]').show();}) + } + if (hidden_section==undefined){ + $(form).children('input[name=section]').remove(); + $(form).append($('').attr('name','section').attr('value',$(Fieldset).attr('id'))); + } + $('.message').fadeOut('slow',function(){$(this).slideUp('slow',function(){$(this).remove();})}); + } + ); + $(form).children('.formMenu').append(menu).append(' '); + }); + if (section!=undefined){ + $(form).children('fieldset[id='+section+']').show(); + }else{ + $(form).children('fieldset:first').show(); + } + }, + + waitMessage:function(){ + var This=this; + var content=$('div[id=content]'); + if (content!=undefined){ + $(content).hide(); + }else{ + $('input').hide();$('select').hide(); + content=$('body'); + } + var text=$('

    ').addClass('message').text(This.text_wait); + This.blinkItem(text); + var box=$('
    ').attr('style','margin: 60px auto auto;width:200px;').append(text); + $(content).before($(box)); + }, + + blinkItem:function(item){ + var This=this; + $(item).fadeOut('slow',function(){$(this).fadeIn('slow',function(){This.blinkItem(this);})}); + } +} \ No newline at end of file diff --git a/js/service.js b/js/service.js new file mode 100644 index 0000000..ec78b52 --- /dev/null +++ b/js/service.js @@ -0,0 +1,17 @@ +/* -- BEGIN LICENSE BLOCK ---------------------------------- + * This file is part of kUtRL, a plugin for Dotclear 2. + * + * Copyright (c) 2009-2011 JC Denis and contributors + * jcdenis@gdwd.com + * + * Licensed under the GPL version 2.0 license. + * A copy of this license is available in LICENSE file or at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * -- END LICENSE BLOCK ------------------------------------*/ + +$(function() { + var kutrlForm=$('#service-form'); + if (kutrlForm!=undefined){ + dotclear.jcTools.formFieldsetToMenu(kutrlForm); + } +}); \ No newline at end of file diff --git a/js/setting.js b/js/setting.js new file mode 100644 index 0000000..b450278 --- /dev/null +++ b/js/setting.js @@ -0,0 +1,17 @@ +/* -- BEGIN LICENSE BLOCK ---------------------------------- + * This file is part of kUtRL, a plugin for Dotclear 2. + * + * Copyright (c) 2009-2011 JC Denis and contributors + * jcdenis@gdwd.com + * + * Licensed under the GPL version 2.0 license. + * A copy of this license is available in LICENSE file or at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * -- END LICENSE BLOCK ------------------------------------*/ + +$(function() { + var kutrlForm=$('#setting-form'); + if (kutrlForm!=undefined){ + dotclear.jcTools.formFieldsetToMenu(kutrlForm); + } +}); \ No newline at end of file diff --git a/locales/en/help/help.html b/locales/en/help/help.html new file mode 100644 index 0000000..bebff89 --- /dev/null +++ b/locales/en/help/help.html @@ -0,0 +1,19 @@ + + + + + kUtRL + + + +

    If you want some help or contribute to the plugin kUtRL, follow these links.

    + + + + \ No newline at end of file diff --git a/locales/en/resources.php b/locales/en/resources.php new file mode 100644 index 0000000..8f6f377 --- /dev/null +++ b/locales/en/resources.php @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/locales/fr/help/help.html b/locales/fr/help/help.html new file mode 100644 index 0000000..e3fa7e1 --- /dev/null +++ b/locales/fr/help/help.html @@ -0,0 +1,19 @@ + + + + + kUtRL + + + +

    Si vous souhaitez plus d'aide ou apporter votre contribution à l'extension kUtRL, voici quelques liens utiles.

    + + + + \ No newline at end of file diff --git a/locales/fr/main.lang.php b/locales/fr/main.lang.php new file mode 100644 index 0000000..c6c7e81 --- /dev/null +++ b/locales/fr/main.lang.php @@ -0,0 +1,522 @@ + \ No newline at end of file diff --git a/locales/fr/main.po b/locales/fr/main.po new file mode 100644 index 0000000..6c58a92 --- /dev/null +++ b/locales/fr/main.po @@ -0,0 +1,679 @@ +# Language: Français +# Module: kUtRL - 2011.03.24 +# Date: 2011-03-24 16:34:14 +# Translated with translater 1.5 + +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: kUtRL 2011.03.24\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: 2011-03-24T16:34:14+00:00\n" +"Last-Translator: JC Denis\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" + +#: _admin.php:19 +#: _widgets.php:22 +#: inc/index.link.php:105 +#: inc/index.links.php:200 +#: inc/index.service.php:38 +#: inc/index.setting.php:70 +#: index.php:44 +#: index.php:45 +msgid "Links shortener" +msgstr "Réducteur de liens" + +#: _admin.php:73 +#: inc/index.links.php:117 +msgid "Short link" +msgstr "Lien court" + +#: _admin.php:90 +msgid "Create short link" +msgstr "Créer un lien court" + +#: _admin.php:96 +#: inc/index.link.php:129 +msgid "Custom short link:" +msgstr "Lien court personnalisé :" + +#: _admin.php:106 +#: _widgets.php:178 +msgid "never followed" +msgstr "jamais suivi" + +#: _admin.php:110 +#: _widgets.php:182 +msgid "followed one time" +msgstr "suivi une fois" + +#: _admin.php:114 +#: _widgets.php:186 +msgid "followed %s times" +msgstr "suivi %s fois" + +#: _admin.php:121 +#: _admin.php:225 +msgid "delete short link" +msgstr "effacer un lien court" + +#: _admin.php:224 +msgid "create short link" +msgstr "créer un lien court" + +#: _public.php:143 +msgid "Failed to verify protected field." +msgstr "Impossible de vérifier le champs de protection." + +#: _public.php:151 +#: inc/index.link.php:34 +#: inc/services/class.bilbolinks.service.php:61 +#: inc/services/class.bitly.service.php:76 +#: inc/services/class.local.service.php:108 +#: inc/services/class.supr.service.php:67 +#: inc/services/class.trim.service.php:69 +#: inc/services/class.yourls.service.php:78 +msgid "Service is not well configured." +msgstr "Le service n'est pas correctement configuré." + +#: _public.php:159 +msgid "This string is not a valid URL." +msgstr "Cette chaine n'est pas un lien valide." + +#: _public.php:167 +#: inc/index.link.php:43 +msgid "This link is too short." +msgstr "Ce lien est trop court." + +#: _public.php:175 +#: inc/index.link.php:46 +msgid "This type of link is not allowed." +msgstr "Ce type de lien n'est pas autorisé." + +#: _public.php:184 +#: inc/index.link.php:49 +msgid "Short links are limited to this blog URL." +msgstr "Les liens courts sont limités à l'URL de ce blog." + +#: _public.php:192 +#: inc/index.link.php:52 +msgid "This link is already a short link." +msgstr "Ce lien est dèjà un lien court." + +#: _public.php:205 +#: _public.php:224 +#: inc/index.link.php:63 +#: inc/index.link.php:84 +msgid "Short link for %s is %s" +msgstr "Le lien court pour %s est %s" + +#: _public.php:216 +msgid "Failed to create short link." +msgstr "Impossible de créer le lien court." + +#: _public.php:233 +#: _public.php:337 +#: _public.php:557 +msgid "New public short URL" +msgstr "Nouvelle URL courte" + +#: _public.php:429 +#: _widgets.php:106 +msgid "Rewrite \"%s\" in next field to show that you are not a robot:" +msgstr "Recopier \"%s\" dans le champs suivant pour montrer que vous n'êtes pas une machine :" + +#: _widgets.php:26 +msgid "Shorten link" +msgstr "Réduire un lien" + +#: _widgets.php:35 +#: _widgets.php:39 +msgid "Top of short links" +msgstr "Top des liens courts" + +#: _widgets.php:42 +msgid "Text: (Use wildcard %rank%, %hash%, %url%, %count%, %counttext%)" +msgstr "Texte : (Ustiliser les jokers %rank%, %hash%, %url%, %count%, %counttext%)" + +#: _widgets.php:45 +msgid "URL length (if truncate)" +msgstr "Longueur de l'URL (si tronqué)" + +#: _widgets.php:49 +msgid "All" +msgstr "Tous" + +#: _widgets.php:50 +msgid "Mini URL" +msgstr "Mini URL" + +#: _widgets.php:51 +msgid "Custom URL" +msgstr "URL personnalisé" + +#: _widgets.php:52 +msgid "Semi-custom" +msgstr "Semi-personnalisé" + +#: _widgets.php:56 +msgid "Semi-custom prefix: (only if you want limit to a particular prefix)" +msgstr "Préfixe des liens semi-personnalisé : (Seulement si vous voulez limiter à un préfixe particulier)" + +#: _widgets.php:60 +msgid "Sort by:" +msgstr "Trier par :" + +#: _widgets.php:62 +msgid "Rank" +msgstr "Rang" + +#: _widgets.php:63 +#: inc/index.links.php:34 +msgid "Hash" +msgstr "Hash" + +#: _widgets.php:73 +msgid "Limit:" +msgstr "Limite :" + +#: _widgets.php:76 +msgid "Hide no followed links" +msgstr "Cacher les liens non suivis" + +#: _widgets.php:102 +#: inc/index.link.php:122 +msgid "Long link:" +msgstr "Lien long :" + +#: _widgets.php:109 +msgid "Create" +msgstr "Créer" + +#: inc/index.link.php:31 +msgid "There is nothing to shorten." +msgstr "I n'y a rien à réduire." + +#: inc/index.link.php:37 +msgid "This service does not allowed custom hash." +msgstr "Ce service n'accepte pas les liens court personnalisés." + +#: inc/index.link.php:40 +msgid "This link is not a valid URL." +msgstr "Ce lien n'est pas valide." + +#: inc/index.link.php:55 +msgid "This custom short url is already taken." +msgstr "Ce lien court personnalisé est déjà pris." + +#: inc/index.link.php:76 +msgid "Failed to create short link. This could be caused by a service failure." +msgstr "Impossible de créé un lien court. Ceci peut être causé par un problème du service." + +#: inc/index.link.php:92 +#: inc/lib.wiki.kutrl.php:73 +msgid "New short URL" +msgstr "Nouvelle URL courte" + +#: inc/index.link.php:109 +#: inc/index.links.php:208 +#: inc/index.service.php:48 +#: inc/index.setting.php:80 +msgid "New link" +msgstr "Nouveau lien" + +#: inc/index.link.php:114 +msgid "You must set an admin service." +msgstr "Vous devez définir un service admin." + +#: inc/index.link.php:121 +msgid "Shorten link using service \"%s\"" +msgstr "Raccourcir un lien en utilisant le service \"%s\"" + +#: inc/index.link.php:131 +msgid "Only if you want a custom short link." +msgstr "Uniquement si vous souhaitez un lien court personnalisé." + +#: inc/index.link.php:136 +msgid "You can use \"bob!!\" if you want a semi-custom link, it starts with \"bob\" and \"!!\" will be replaced by an increment value." +msgstr "Vous pouvez utiliser \"bob!!\" si vous souhaitez un lien semi-personnalisé, il commencera par \"bob\" et \"!!\" sera remplacé par une valeur incrémentale." + +#: inc/index.links.php:23 +msgid "No short link" +msgstr "Pas de lien court" + +#: inc/index.links.php:37 +msgid "Service" +msgstr "Service" + +#: inc/index.links.php:116 +msgid "Long link" +msgstr "Lien long" + +#: inc/index.links.php:131 +#: inc/index.setting.php:65 +msgid "Disabled" +msgstr "Désactiver" + +#: inc/index.links.php:221 +msgid "Service:" +msgstr "Service :" + +#: inc/index.links.php:251 +msgid "Delete selected short links" +msgstr "Effacer les liens sélectionnés" + +#: inc/index.service.php:47 +#: index.php:40 +msgid "Services" +msgstr "Services" + +#: inc/index.service.php:62 +msgid "%s API is well configured and runing." +msgstr "L'API %s est correctement configurée et est fonctionnelle." + +#: inc/index.service.php:63 +msgid "Failed to test %s API." +msgstr "Impossible de tester l'API %s." + +#: inc/index.service.php:72 +msgid "homepage" +msgstr "page d'accueil" + +#: inc/index.service.php:72 +msgid "Learn more about %s." +msgstr "En savoir plus à propos de %s." + +#: inc/index.setting.php:79 +#: index.php:39 +msgid "Settings" +msgstr "Paramètres" + +#: inc/index.setting.php:84 +msgid "Plugin activation" +msgstr "Activation de l'extension" + +#: inc/index.setting.php:87 +msgid "Enable plugin" +msgstr "Activer l'extension" + +#: inc/index.setting.php:90 +msgid "General rules" +msgstr "Réglages" + +#: inc/index.setting.php:93 +msgid "Allow short link for external URL" +msgstr "Autoriser les liens court sur des URLs externes" + +#: inc/index.setting.php:94 +msgid "Not only link started with this blog URL could be shortened." +msgstr "Ne pas limiter la création de liens courts aux liens commençant par l'URL du blog." + +#: inc/index.setting.php:97 +msgid "Passive mode" +msgstr "Mode passif" + +#: inc/index.setting.php:98 +msgid "If this extension is disabled and the passive mode is enabled, \"kutrl\" tags (like EntryKurl) will display long urls instead of nothing on templates." +msgstr "Si cette extension est désactivée et que le mode passif est activé, les balises \"kutrl\" (comme EntryKutrl) afficheront les liens longs au lieu de rien." + +#: inc/index.setting.php:101 +msgid "Active mode" +msgstr "Mode actif" + +#: inc/index.setting.php:102 +msgid "If the active mode is enabled, all know default template tags (like EntryURL) will display short urls instead of long ones on templates." +msgstr "Si le mode actif est acitvé, les balises de thème (comme EntryURL) afficheront les liens court au lieu des longs." + +#: inc/index.setting.php:103 +msgid "You can disable URL shortening for a specific template tag by adding attribute disable_kutrl=\"1\" to it." +msgstr "Vous pouvez désactiver la réduction d'URL pour une balise de template spécifique en lui ajoutant l'attribut disable_kutrl=\"1\"" + +#: inc/index.setting.php:106 +msgid "Create short link for new entries" +msgstr "Créer un lien court pour les nouveaux billets" + +#: inc/index.setting.php:107 +msgid "This can be changed on page of creation/edition of an entry." +msgstr "Ceci peut être changé sur la page d'édition / création d'un billet." + +#: inc/index.setting.php:110 +msgid "Default services" +msgstr "Services par défaut" + +#: inc/index.setting.php:117 +msgid "Administration:" +msgstr "Administration :" + +#: inc/index.setting.php:120 +msgid "Service to use in this admin page and on edit page of an entry." +msgstr "Service à utiliser sur cette page d'administration ou sur la page d'édition d'un billet." + +#: inc/index.setting.php:127 +msgid "Extensions:" +msgstr "Extensions :" + +#: inc/index.setting.php:130 +msgid "Service to use on third part plugins." +msgstr "Service à utiliser par les plugins tiers" + +#: inc/index.setting.php:137 +msgid "Templates:" +msgstr "Templates :" + +#: inc/index.setting.php:140 +msgid "Shorten links automatically when using template value like \"EntryKutrl\"." +msgstr "Réduit automatiquement les liens des templates utilisant les balises telles que \"EntryKutrl\"." + +#: inc/index.setting.php:147 +msgid "Contents:" +msgstr "Contenus :" + +#: inc/index.setting.php:150 +msgid "Shorten links automatically found in contents using wiki synthax." +msgstr "Réduit automatiquement les liens des contenus utilisant la syntax wiki." + +#: inc/lib.kutrl.activityreport.php:17 +msgid "Plugin kUtRL" +msgstr "Extension kUtRL" + +#: inc/lib.kutrl.activityreport.php:23 +msgid "Short link creation" +msgstr "Création de lien court" + +#: inc/lib.kutrl.activityreport.php:24 +msgid "New short link of type \"%s\" and hash \"%s\" was created." +msgstr "Un nouveau lien court de type \"%s\" et de hash \"%s\" a été créé." + +#: inc/lib.kutrl.srv.php:81 +#: inc/services/class.default.service.php:42 +msgid "There is nothing to configure for this service." +msgstr "Il n'y a rien à configurer pour ce service." + +#: inc/lib.wiki.kutrl.php:67 +msgid "%s (Shorten with %s)" +msgstr "% (réduit avec %s)" + +#: inc/services/class.bilbolinks.service.php:49 +#: inc/services/class.yourls.service.php:54 +msgid "Url of the service:" +msgstr "URL du service :" + +#: inc/services/class.bilbolinks.service.php:53 +msgid "This is the root URL of the \"bilbolinks\" service you want to use. Ex: \"http://tux-pla.net/\"." +msgstr "Ceci est l'URL du service bilbolinks que vous souhaitez utiliser. Ex: \"http://tux-pla.net/\"." + +#: inc/services/class.bilbolinks.service.php:68 +#: inc/services/class.bilbolinks.service.php:80 +#: inc/services/class.custom.service.php:95 +#: inc/services/class.custom.service.php:108 +#: inc/services/class.default.service.php:66 +#: inc/services/class.default.service.php:79 +#: inc/services/class.isgd.service.php:32 +#: inc/services/class.isgd.service.php:44 +#: inc/services/class.shortto.service.php:32 +#: inc/services/class.shortto.service.php:44 +#: inc/services/class.trim.service.php:79 +#: inc/services/class.trim.service.php:99 +#: inc/services/class.yourls.service.php:87 +#: inc/services/class.yourls.service.php:107 +msgid "Service is unavailable." +msgstr "Le service n'est pas disponible." + +#: inc/services/class.bilbolinks.service.php:85 +#: inc/services/class.trim.service.php:110 +msgid "Service rate limit exceeded." +msgstr "La limitation d'envoie au service est atteinte." + +#: inc/services/class.bitly.service.php:51 +#: inc/services/class.supr.service.php:49 +#: inc/services/class.trim.service.php:51 +#: inc/services/class.yourls.service.php:60 +msgid "Login:" +msgstr "Identifiant :" + +#: inc/services/class.bitly.service.php:55 +#: inc/services/class.supr.service.php:53 +msgid "This is your login to sign up to %s" +msgstr "C'est votre identifiant pour vous connecter sur %s" + +#: inc/services/class.bitly.service.php:57 +#: inc/services/class.supr.service.php:55 +msgid "API Key:" +msgstr "Clé API :" + +#: inc/services/class.bitly.service.php:61 +#: inc/services/class.supr.service.php:59 +msgid "This is your personnal %s API key. You can find it on your account page." +msgstr "C'est votre clé personnelle de l'API %s. Vous pouvez la trouver sur la page de votre compte." + +#: inc/services/class.bitly.service.php:65 +msgid "Publish history" +msgstr "Publier l'historique" + +#: inc/services/class.bitly.service.php:68 +msgid "This publish all short links on your bit.ly public page." +msgstr "Ceci publie tous vos liens sur votre page public bit.ly" + +#: inc/services/class.bitly.service.php:84 +#: inc/services/class.bitly.service.php:106 +#: inc/services/class.googl.service.php:40 +#: inc/services/class.googl.service.php:61 +#: inc/services/class.supr.service.php:75 +#: inc/services/class.supr.service.php:98 +msgid "Failed to call service." +msgstr "Impossible d'appeler le service." + +#: inc/services/class.bitly.service.php:93 +#: inc/services/class.bitly.service.php:115 +#: inc/services/class.supr.service.php:85 +#: inc/services/class.supr.service.php:108 +msgid "An error occured with code %s and message \"%s\"" +msgstr "Une erreur est survenu avec le code \"%s\" et le message \"%s\"" + +#: inc/services/class.custom.service.php:65 +msgid "You can set a configurable service." +msgstr "Vous pouvez configurer un service particulier." + +#: inc/services/class.custom.service.php:66 +msgid "It consists on a simple query to an URL with only one param." +msgstr "Il effectue une simple requête à une URL avec un seul paramètre." + +#: inc/services/class.custom.service.php:67 +msgid "It must respond with a http code 200 on success." +msgstr "Il doit répondre avec un code HTTP de 200 en cas de succès" + +#: inc/services/class.custom.service.php:68 +msgid "It must returned the short URL (or only hash) in clear text." +msgstr "Il doit retourner l'URL courte (ou seulement le hash) en texte clair." + +#: inc/services/class.custom.service.php:69 +msgid "API URL:" +msgstr "URL de l'API:" + +#: inc/services/class.custom.service.php:72 +msgid "Full path to API of the URL shortener. ex: \"http://is.gd/api.php\"" +msgstr "Chemin complet vers l'API. ex: \"http://is.gd.php\"" + +#: inc/services/class.custom.service.php:73 +#: inc/services/class.default.service.php:52 +msgid "Short URL domain:" +msgstr "Domaine des URLs courtes:" + +#: inc/services/class.custom.service.php:76 +msgid "Common part of the short URL. ex: \"http://is.gd/\"" +msgstr "Partie commune aux URLs courtes. ex: \"http://is.gd/\"" + +#: inc/services/class.custom.service.php:77 +msgid "API URL param:" +msgstr "Paramètre de l'URL" + +#: inc/services/class.custom.service.php:80 +msgid "Param of the query. ex: \"longurl\"" +msgstr "Paramètre de la raquête. ex: \"longurl\"" + +#: inc/services/class.custom.service.php:83 +msgid "Encode URL" +msgstr "Encoder l'URL à raccourcir" + +#: inc/services/class.default.service.php:44 +msgid "This service is set to:" +msgstr "Ce service est règlé comme suit:" + +#: inc/services/class.default.service.php:48 +msgid "Full API URL:" +msgstr "URL complet vers l'API:" + +#: inc/services/class.default.service.php:50 +msgid "Query param:" +msgstr "Paramètre de la requête:" + +#: inc/services/class.default.service.php:54 +msgid "Encode URL:" +msgstr "Encodage des URLs à raccourcir:" + +#: inc/services/class.local.service.php:48 +msgid "Settings:" +msgstr "Paramètres :" + +#: inc/services/class.local.service.php:50 +msgid "Allowed protocols:" +msgstr "Protocoles autorisés :" + +#: inc/services/class.local.service.php:55 +msgid "Use comma seperated list like: \"http:,https:,ftp:\"" +msgstr "Utiliser une virgule pour séparer la liste des protocoles. Ex: \"http:,https:,ftp:\"" + +#: inc/services/class.local.service.php:60 +msgid "Enable public page for visitors to shorten links" +msgstr "Activer la page publique pour que les visiteurs puissent réduire des liens" + +#: inc/services/class.local.service.php:63 +msgid "CSS:" +msgstr "CSS :" + +#: inc/services/class.local.service.php:66 +msgid "You can add here special cascading style sheet. Body of page has class \"dc-kutrl\" and widgets have class \"shortenkutrlwidget\" and \"rankkutrlwidget\"." +msgstr "Vous pouvez ajouter des styles ici. La balise \"body\" a la class \"dc-kutrl\" et les widgets ont les class \"shortenkutrlwidget\" et \"rankkutrlwidget\"." + +#: inc/services/class.local.service.php:70 +msgid "Enable special 404 error public page for unknow urls" +msgstr "Activer la page spéciale d'erreur 404 pour les liens inconnus" + +#: inc/services/class.local.service.php:72 +msgid "If this is not activated, the default 404 page of the theme will be display." +msgstr "Si cette option est désactivée, la page d'erreur 404 par défaut du thème sera utilisée." + +#: inc/services/class.local.service.php:76 +msgid "Note:" +msgstr "Note :" + +#: inc/services/class.local.service.php:78 +msgid "This service use your own Blog to shorten and serve URL." +msgstr "Ce service utilise votre propre blog pour réduire et servir des liens." + +#: inc/services/class.local.service.php:79 +msgid "This means that with this service short links start with \"%s\"." +msgstr "Cela signifie qu'avec ce service vos liens courts commencent par \"%s\"." + +#: inc/services/class.local.service.php:82 +msgid "You can use Dotclear's plugin called myUrlHandlers to change short links prefix on your blog." +msgstr "Vous pouvez utiliser l'extension myUrlHandlers pour Dotclear afin de changer le prefix de vos liens courts depuis votre blog." + +#: inc/services/class.local.service.php:88 +msgid "We recommand that you use a rewrite engine in order to remove 'index.php' from your blog's URL." +msgstr "Nous vous recommandons d'utiliser la réécriture d'URL pour supprimer 'index.php de l'URL de votre blog." + +#: inc/services/class.local.service.php:90 +msgid "You can find more about this on the Dotclear's documentation." +msgstr "Vous trouverez plus d'information à ce sujet dans la documentation Dotclear." + +#: inc/services/class.local.service.php:95 +msgid "There are two templates delivered with kUtRL, if you do not use default theme, you may adapt them to yours." +msgstr "Il y a deux templates livrés avec kUtRL, si vous n'utilisez pas le thème par défaut, vous devrez peut-être les adapter au votre." + +#: inc/services/class.local.service.php:96 +msgid "Files are in plugin directory /default-templates, just copy them into your theme and edit them." +msgstr "Les fichiers sont dans le répertoire /default-templates du plugin, copiez les dans votre thème et modifiez les." + +#: inc/services/class.local.service.php:139 +msgid "Custom short link is already taken." +msgstr "Le lien court personnalisé est déjà pris." + +#: inc/services/class.local.service.php:149 +msgid "Custom short link is not valid." +msgstr "Le lien court personnalisé n'est pas valide." + +#: inc/services/class.local.service.php:160 +msgid "Failed to save link." +msgstr "Impossible d'enregistrer le lien." + +#: inc/services/class.trim.service.php:55 +msgid "This is your login to sign up to tr.im." +msgstr "Ceci est votre login d'inscription sur tr.im." + +#: inc/services/class.trim.service.php:61 +msgid "This is your password to sign up to tr.im." +msgstr "Ceci est votre mot de passe d'inscription sur tr.im." + +#: inc/services/class.trim.service.php:74 +msgid "Prevent service rate limit." +msgstr "Prévention de la limitation d'envoie du service." + +#: inc/services/class.trim.service.php:88 +#: inc/services/class.yourls.service.php:96 +msgid "Authentication to service failed." +msgstr "Authentification au service échoué." + +#: inc/services/class.trim.service.php:122 +#: inc/services/class.yourls.service.php:122 +msgid "Unreadable service response." +msgstr "La réponse du service n'est pas lisible." + +#: inc/services/class.yourls.service.php:58 +msgid "This is the URL of the YOURLS service you want to use. Ex: \"http://www.smaller.org/api.php\"." +msgstr "Ceci est l'URL du service YOURLS que vous voulez utiliser. Ex: \"http://www.smaller.org/api.php\"." + +#: inc/services/class.yourls.service.php:64 +msgid "This is your user name to sign up to this YOURLS service." +msgstr "Ceci est votre nom d'utilisateur pour vous connecter à ce service YOURLS." + +#: inc/services/class.yourls.service.php:70 +msgid "This is your password to sign up to this YOURLS service." +msgstr "Ceci est votre mot de passe pour vous connecter à ce service YOURLS." + +#: index.php:31 +msgid "Please wait" +msgstr "Veuillez patienter" + +#: index.php:39 +msgid "Configure extension" +msgstr "Configurer l'extension" + +#: index.php:40 +msgid "Configure services" +msgstr "Configurer les services" + +#: index.php:52 +msgid "Configuration successfully saved" +msgstr "Configuration sauvegardée avec succès" + +#: index.php:53 +msgid "Services successfully updated" +msgstr "Services mises à jour avec succès" + +#: index.php:54 +msgid "Link successfully shorten" +msgstr "Lien raccourcie avec succès" + +#: index.php:55 +msgid "Links successfully deleted" +msgstr "Liens supprimés avec succès" + +msgid "This is your login to sign up to bit.ly." +msgstr "Ceci est votre login d'inscription sur bit.ly." + +msgid "This is your personnal bit.ly API key. You can find it on your account page." +msgstr "Ceci est votre clé personnelle pour l'API bit.ly. Vous pouvez la trouver sur la page de vore compte." + diff --git a/locales/fr/resources.php b/locales/fr/resources.php new file mode 100644 index 0000000..8f6f377 --- /dev/null +++ b/locales/fr/resources.php @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/release.txt b/release.txt new file mode 100644 index 0000000..1044682 --- /dev/null +++ b/release.txt @@ -0,0 +1,85 @@ +todo + - Added public page of the list of know urls and in/visible status + - Added passworded links + +2011.04.01 + * Changed version numbering + * Added service su.pr (stumbleUpon) + * Fixed wiki settings (thanks @ploum ) + +1.0 20110213 + * Added generic class to easlily access services + * Changed generic service class (and class extend it) + * Fixed config of default service + * Fixed display of admin fake section + * Added checkbox helpers on admin + +0.6.1 20110130 + * Cleaned up script + +0.6 20110118 'prepare the soCial révolution' + * Added default defined service (for all blogs of a multiblog) + * Added configurable external service + * Added goog.gl client service (first step) + * Added default settings for third part plugins + * Added behaviors after short link creation + * Added attribute to disable URL shortining on template tag with 'active mode' (fixed bug on URL of POST form) + * Remove all messenger functions: this is to another plugin to do that + * Remove priority in plugin definition + +0.5 20100909 + * Removed old Twitter functions + * Added StatusNet small functions (Identica) + * Required plugin Tac for Twitter ability + * Added YOURLS client service + +0.4.2 20100809 + * Fixed bug on dcTwitter shorten service + * Fixed bug on custom local link + * Added category URL to active mode + * Added priority to plugin definition + +0.4.1 20100701 + * Fixed multiple bugs + +0.4 20100628 + * Switched to DC 2.2 + * Fixed no short urls on preview mode + * Fixed lock hash of deleted urls + * Fixed hide new short url widget on kutrl pages + * Fixed typo + * Added active mode that shorten urls on default template values + * Added special tweeter message for post (can include post title) + * Added kutrl special 404 page + +0.3.3 20100528 + * Fixed settings in tweeter class + * Renamed tweeter class + +0.3.2 20100525 + * FIxed minor bugs + * Fixed DC 2.1.7 + +0.3 20100414 + * Added DC 2.2 compatibility (new settings) + * Added semi-custom hash on kUtRL service + * Added status update for Twitter/Identi.ca on new short link + * Added services error management (first step) + * Added options to widgets + * Upgraded bitly service to v3 + * Changed admin design + +0.2 20091223 + * Fixed public redirection with suffix + * Added short.to service + +0.1.2 20091212 + * Added option to short url of new entry by default + * Fixed typo + +0.1.1 20091212 + * Added option to display long url when unactive + * Fixed support of kutrl in feeds + +0.1 20091209 + * First lab release \ No newline at end of file